Как мы можем выполнять модульные тесты против манипуляций с DOM?

Введение в QUnit на netTuts.com порождает интересный обмен мнениями (так и не разрешенный) о том, как применять модульные тесты к действиям, которые манипулируют DOM. Следующая цитата (Алекс Йорк) доходит до сути:

Было бы неплохо, если бы у вас была такая функция:

function add(a, b) { var result = a + b; $("input#ResultTestBox").val(результат);

В приведенном выше тесте я хотел бы проверить две вещи: добавление a и b и правильное размещение результата в элементе DOM. Я хотел бы протестировать вторую вещь, предоставив некоторый фиктивный HTML. Возможный?

Но, как я уже сказал... нерешенный. Разрешимый?


person justSteve    schedule 20.10.2010    source источник


Ответы (3)


Последняя версия QUnit поддерживает элемент #qunit-fixture, который позволяет добавлять HTML на веб-страницу QUnit.

Например, в вашем HTML:

<ol id="qunit-tests"></ol>
<div id="qunit-fixture">test markup, will be hidden</div>

и в вашем JavaScript:

$('<input id="ResultTestBox" type="text"/>').appendTo('#qunit-fixture');
var result = add(a, b);

equals(result, $('input#ResultTestBox').val(), "testing result box value");
person Charles Anderson    schedule 14.11.2010
comment
Как проходит модульное тестирование, когда вы на самом деле основываете его на реальных манипуляциях с домом? - person tusharmath; 03.09.2014
comment
@Tushar, это зависит от того, какое из 26 определений модульного тестирования вы используете. Пока тесты могут выполняться независимо друг от друга, они являются модульными тестами в соответствии с некоторыми определениями. (например, в книге «Разработка через тестирование на примере» Кента Бека) - person herman; 31.05.2016

Наверняка вас на самом деле заботит то, что метод val вызывается для возвращаемого значения $(“input#ResultTestBox”) — вам не нужно тестировать функциональность самого метода jQuery. Почему бы не внедрить фиктивную реализацию объекта jQuery и протестировать ее?

person Steve Greatrex    schedule 15.11.2010
comment
Как вы создаете фиктивные объекты jQuery, не теряя самого jQuery? Нравится идея, но возникают проблемы с визуализацией того, как вы будете создавать моки в коде. - person Sukima; 15.06.2011
comment
@Sukima, вы бы реорганизовали свой исходный код, чтобы объект $ передавался в качестве параметра и по умолчанию делал значение этого параметра jQuery. Затем в ваших модульных тестах вы передаете свой фиктивный объект - person Steve Greatrex; 15.06.2011
comment
Насмешка (по крайней мере, для вещей, отличных от удаленных вызовов, запросов к базе данных...) - это запах кода. Если вы можете проверить результат звонка, а не констатировать, что сам звонок произошел, это, как правило, гораздо лучше. - person herman; 31.05.2016
comment
@herman, если мой код зависит от реализации службы, почему бы мне не издеваться над службой? Если я изменю поведение службы, мне не придется менять модульные тесты для каждой зависимости, чтобы отразить это изменение. Если я нарушу поведение службы, модульные тесты для каждой зависимости также не должны нарушаться. - person Steve Greatrex; 01.06.2016
comment
@SteveGreatrex, если вы реорганизуете код таким образом, чтобы изменить интерфейс службы (например, вы добавили в службу еще несколько вещей, которые ранее повторялись в каждом клиенте), но без изменения общего поведения, тогда вы сможете проверить что ваш рефакторинг ничего не сломал, запустив тесты, не меняя их все сначала. Другими словами, избегать насмешек означает избегать тесной связи между тестами и кодом реализации. - person herman; 01.06.2016
comment
@SteveGreatrex В этом конкретном случае он может захотеть заменить использование jQuery в своем производственном коде на простой старый javascript и использовать существующие тесты, чтобы убедиться, что поведение не изменилось. С вашим решением тест не сработает, даже если код в порядке. - person herman; 01.06.2016
comment
@herman интересная идея. Я бы сказал, что в вашем примере он должен провести модульное тестирование своей простой JS-реализации $, чтобы убедиться, что она ведет себя так же, как jQuery. Для меня то, что вы описываете, является интеграционным тестом, а не модульным тестом. - person Steve Greatrex; 01.06.2016
comment
@SteveGreatrex 1) В примере я не имел в виду, что он заменит $ своей собственной реализацией. Я имел в виду, что он заменит код для обновления значения чем-то вроде document.querySelector('selector').value = ... вместо использования jQuery. Теперь с вашим решением внезапно тест должен имитировать document вместо $. 2) даже если он сделает абстракцию этого и внедрит зависимость, которая использует jQuery или простой JS, тогда, когда он захочет протестировать простую версию JS, у него все еще будет исходная проблема. - person herman; 01.06.2016
comment
@SteveGreatrex 3) Является ли это модульным тестом или нет, зависит от того, какое из 26 определений модульного теста вы используете. Я называю тест интеграционным тестом только в том случае, если вызываются разные системы (службы HTTP REST, база данных и т. д.). Но это всего лишь терминология, не меняющая полезности (или ее отсутствия) теста. - person herman; 01.06.2016

Вы можете запустить их в env.js, если не хотите возиться с созданием html страницы песочницы для всех ваших тестов.

person Sudhir Jonathan    schedule 14.11.2010