Тестирование частных функций в 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 написал красивые статьи: