Тестирование частных функций в javascript
Я использую шаблон модуля в Javascript, чтобы отделить мой публичный интерфейс от частной реализации. Чтобы упростить то, что я делаю, мой код генерирует диаграмму. Диаграмма состоит из нескольких частей (оси, метки, сюжет, легенда и т.д.). Мой код выглядит так:
var Graph = function() {
var private_data;
function draw_legend() { ... }
function draw_plot() { ... }
function helper_func() { ... }
...
return {
add_data: function(data) {
private_data = data;
},
draw: function() {
draw_legend()
draw_plot()
}
}
}
Некоторые люди выступают за тестирование только публичного интерфейса ваших классов, что имеет смысл, но мне бы очень хотелось пройти некоторые тесты для тестирования каждого из компонентов по отдельности. Если я испортил свою функцию draw_legend(), я бы хотел, чтобы этот тест завершился неудачей, а не тест для функции public draw(). Я нахожусь на неправильном пути здесь?
Я мог бы разделить каждый из компонентов в разных классах, например, создать класс Legend. Но кажется глупым создать класс для того, что иногда составляет всего 5-10 строк кода, и это было бы ужасно, потому что мне нужно было бы передать кучу частного состояния. И я не смог бы проверить свои вспомогательные функции. Должен ли я это делать? Должен ли я сосать его и проверять только общественность()? Или есть другое решение?
Ответы
Ответ 1
Нет доступа к внутренним функциям (частным) из внешней области. Если вы хотите протестировать внутренние функции, вы можете рассмотреть возможность добавления публичного метода только для целей тестирования. Если вы используете какую-либо среду сборки, например ant, вы можете предварительно обработать файл javascript для производства и удалить эти тестовые функции.
Фактически Javascript является объектно-ориентированным языком. Это просто не типично напечатано.
Ответ 2
Мое решение - это всего лишь немного взломать. Пример QUnit:
В верхней части теста Qunit html я заявил:
var TEST_AVAILABLE = true;
В проверяемом классе у меня есть такой фрагмент:
if(TEST_AVAILABLE){
this.test={
hasDraft:hasDraft,
isInterpIdIn:isInterpIdIn,
// other private methods
};
}
В QUnit вы можете проверить
test( "hello booth", function() {
var b = new Booth();
ok(b);
ok(b.test);
ok(!b.test.hasDraft());
});
Ответ 3
У меня аналогичная проблема. Решение, которое я придумал, - это не то, что мне нравится, но оно выполняет эту работу, и там нет лучшего решения, которое я могу найти.
function Graph()
{
this.Test = function _Test(expressionStr) { return eval(expressionStr); }
var private_data;
function draw_legend() { ... }
function draw_plot() { ... }
function helper_func() { ... }
...
}
Чтобы проверить:
var g = new Graph();
g.Test("helper_func()") == something;
g.Test("private_data") == something2
Ответ 4
На самом деле существует простой способ. Вы можете использовать ajax для загрузки script и вставить функцию, которая предоставляет частные функции. У меня есть пример здесь, который использует qUnit и jQuery. Но я уверен, что то же самое можно легко выполнить с использованием чистого Javascript.
Ответ 5
На объектно-ориентированном языке обычно unit test методы защищены, если класс класса наследуется от тестируемого класса.
Конечно, Javascript на самом деле не является объектно-ориентированным языком, и этот шаблон не позволяет наследовать.
Мне кажется, вам нужно либо публиковать свои методы, либо отказаться от тестирования модулей.
Ответ 6
Существует только один правильный вариант: Различные сборки для тестирования и производства
1) отметьте только части разработки
/* test-code */
api._foo = foo
/* end-test-code */
2) разделите их позже...;)
grunt.registerTask("deploy",
[
"concat",
"strip-code",
...
@philwalton написал красивые статьи: