Главная страница

ответы. ответы на вопросы. 1. Agile, tdd и bdd


Скачать 182.7 Kb.
Название1. Agile, tdd и bdd
Анкорответы
Дата07.02.2022
Размер182.7 Kb.
Формат файлаdocx
Имя файлаответы на вопросы.docx
ТипТесты
#353991

1. Agile, TDD и BDD


Обычно автоматические модульные и интеграционные тесты рекомендуется создавать для выполненного функционала для того, чтобы уменьшить риск регрессионных ошибок при изменении кода в будущем. В случае с JavaScript подобные тесты могут существенно упростить проверку работоспособности системы в различных браузерах путем автоматизации действий по обеспечению такой проверки. Кроме того, добрую службу может сослужить написание модульного или интеграционного теста на каждый закрытый баг в продукте.

Существуют также методики программирования, которые требуют начинать кодирование логики с написания модульного теста: Test-Driven Development (TDD) и Behavior-Driven Development (BDD). Они часто используются в Agile-процессе. Рассмотрим их особенности подробнее.

Test-Driven Development

Разработка через тестирование — это итеративный процесс написания кода, в котором повторяются следующие четыре шага:

Шаг 1. Перед тем, как добавить новый фрагмент логики, создайте модульный тест для проверки этой логики;

Шаг 2. Запустите тест и убедитесь в том, что он не проходит;

Шаг 3. Напишите самый простой код, который заставит тест выполниться успешно;

Шаг 4. Отредактируйте код в соответствии с требованиями к качеству, уберите дублирование кода и убедитесь в том, что тест проходит успешно.

Под модульным тестом понимается код, который тестирует работу некоторого компонента (модуля) в изолированной среде. Под интеграционным тестом понимается код, который тестирует совместную работу нескольких компонентов. Чтобы протестировать модуль в изолированной среде в случае, когда он зависит от других модулей, применяются «дублёры» (test doubles).

Test Doubles

Деление вспомогательных объектов, используемых при модульном тестировании, на категории берёт своё начало с книги xUnit Test Patterns Жерара Мезароса (Gerard Meszaros). Эти категории обобщённо называются «тестовые дублёры» (test doubles). Дублёры бывают следующих видов:

  • Stub;

  • Mock;

  • Spy;

  • Fake;

  • Dummy.

Stub — это вспомогательный объект, выходные значения для которого задаются заранее. Он используется для того, что имитировать интерфейс зависимого компонента.

Mock — это вспомогательный объект, поведение которого задаётся заранее. Он используется для того, что имитировать интерфейс зависимого компонента и проверить в ходе теста, правильно ли он используется.

Spy — это вспомогательный объект для инспектирования вызываемых методов и передаваемых им параметров в ходе теста.

Fake — это вспомогательный объект, реализующий интерфейс зависимого компонента в упрощённом виде. Например, для целей модульного тестирования можно завести базу данных в памяти вместо реляционной базы данных, которая используется в рабочей версии продукта.

Dummy — это вспомогательный объект, указание или передача которого требуется сигнатурой метода или любым другим контрактом, но реальное значение никогда не используется.

Разница между Stub и Mock заключается в способе проверки результатов работы теста. В случае со Stub в конце теста проверяется состояние объекта. В случае с Mock в ходе теста проверяется то, что объект используется именно так, как было описано при регистрации. Подробности можно узнать из заметки Mocks Aren't Stubs Мартина Фаулера (Martin Fowler), а я приведу тут лишь пример.

Stub

Mock

"test connect should start polling": function () {

this.client.url = "/my/url";

sinon.stub(ajax, "poll").returns({});

this.client.connect();

sinon.assert.calledWith(ajax.poll, "/my/url");

}

 

"test connect should start polling": function () {

this.client.url = "/my/url";

var mock = sinon.mock(ajax)

mock.expects("poll")

  .withArgs("/my/url")

  .returns({});

this.client.connect();

mock.verify();

}

 

Behavior-Driven Development

Итерационный подход к разработке программного обеспечения через реализацию функциональных требований — это уже знакомый нам стиль разработки через тестирование, ориентированный на результат. В процессе BDD последовательно выполняются следующие три шага:

Шаг 1. Определение функциональных требований к реализуемому модулю в виде тестов;

Шаг 2. Кодирование модуля;

Шаг 3. Проверка того, что все пожелания заказчика или бизнес-аналитика (BA) выполнены путем проверки результатов запуска тестов.

При написании тестов в стиле BDD очень удобно использовать Mock-объекты из-за того, что они отлично отражают требования по функциональной части для компонента. Таким образом, тесты в процессе BDD могут служить формализованным представлением задачи (user story) в терминах Scrum, что позволяет экономить время на написании технического задания и документации по готовому продукту.

Каким должен быть фреймворк для модульного тестирования JavaScript?

Полноценный инструмент для модульного и интеграционного тестирования JavaScript должен состоять из следующих компонентов:

  • Assertion library (набор методов для проверки состояния компонента в конце каждого теста);

  • Mock library (инструмент для генерации Mock-объектов и других "дублёров");

  • Test runner (инструмент автоматического запуска тестов с поддержкой большинства браузеров, включая браузеры iOS и Android);

  • Блока подключения к популярным системам непрерывной интеграции (Continuous Integration).

Стратегии модульного тестирования кода на языке JavaScript

Сегодня существует три стратегии модульного тестирования JavaScript кода (подробнее — в третьей главе книги Test-Driven JavaScript Development Кристиана Йохансена (Christian Johansen)):

  • In-Browser тестирование;

  • Headless тестирование;

  • Тестирование по пути JsTestDriver.

In-Browser тестирование предполагает запуск всех модульных и интеграционных тестов из HTML-страницы, которую разработчик открывает в нужных браузерах самостоятельно. Такой подход прост и интуитивно понятен. Однако его минусом является то, что он не предусматривает возможности включения подобных тестов в Continuous Integration. Кроме того, запускать вручную HTML-страницу в десяти и более браузерах и постоянно нажимать "F5" может быть утомительно для разработчика.

Headless тестирование заключается в том, что весь JavaScript код тестируется на эмуляторе, который может быть написан на Java, Ruby, JavaScript, C++ и т.д. Самым известным эмулятором на сегодняшний день является PhantomJS, который представляет собой движок WebKit, запускаемый из командной строки. Из преимуществ эмулятора можно отметить то, что его легко можно использовать в Continuous Integration, а также то, что он позволяет автоматизировать запуск всех тестов из командной строки. Однако у такого подхода есть существенный недостаток — код не тестируется на реальных браузерах, поэтому есть риск пропустить ошибки браузера, которые не воспроизводятся на эмуляторе. До появления JsTestDriver можно было часто встретить то, что In-Browser тестирование комбинируется с Headless тестированием, поскольку они прекрасно дополняют друг друга.

JsTestDriver — это клиент-серверное приложение на Java для автоматического тестирования кода на языке JavaScript в реальных браузерах. В отличие от предыдущих двух стратегий JsTestDriver не имеет недостатков. А среди достоинств можно выделить следующие:

  • Тестирование кода в реальных браузерах;

  • Поддержка Continuous Integration;

  • Запуск всех тестов из командной строки;

  • Работа с любым числом браузеров, даже браузерами iOS и Android.

Такие возможности достигаются за счёт того, что система разделена на клиентскую и серверную части. Сервер JsTestDriver — это компонент, который следит за подключёнными к нему браузерами и использует их для запуска тестов по запросу клиента. Браузер подключается к серверу JsTestDriver вручную путём открытия страницы по адресу и порту, на котором сконфигурирован сервер. Клиентом может выступать расширение для IDE, командная строка или сервер Continuous Integration.

В настоящее время стиль JsTestDriver используется и в других системах запуска тестов для JavaScript, например, Karma или Buster.JS, а сам JsTestDriver считается устаревшим.

Сравнение популярных библиотек для модульного тестирования JavaScript

Мы провели сравнительный анализ трёх популярных библиотек для модульного тестирования JavaScript кода: JasmineqUnit и YUI Test. В первую очередь нас интересовало удобство написания тестов, отсутствие привязанности к DOM-модели браузера (на тот случай, если появится модуль для Node.js), поддержка асинхронных тестов и встроенные средства работы с Test Doubles.

 

qUnit

Jasmine

YUI Test

Лицензия

MIT

MIT

BSD

Зависимость от DOM-модели браузера

Зависит. Также есть отдельная NPM-инсталляция для Node.js, не привязанная к браузеру

Не зависит

Включен в YUI library, а также поставляется как отдельная NPM-инсталляция, не привязанная к браузеру

Test Doubles

Нет

Есть поддержка Spy, имеются Fake-объекты для XmlHttpRequest и JavaScript setTimeout/setInterval

Поддержка Mock-объектов (Y.Mock)

Асинхронные тесты

Да, QUnit.asyncTest

Да, каждый тест может принимать параметр done

Да, каждый тест имеет методы wait и resume

Поддержка синтаксиса BDD

Да, через расширение

Да

Нет













Классический синтаксис qUnit:



Стиль BDD для qUnit:



Синтаксис Jasmine:



Синтаксис YUI Test:


2. По мере роста нашего приложения, мы обычно хотим разделить его на много файлов, так называемых «модулей». Модуль обычно содержит класс или библиотеку с функциями.

Долгое время в JavaScript отсутствовал синтаксис модулей на уровне языка. Это не было проблемой, потому что первые скрипты были маленькими и простыми. В модулях не было необходимости.

Но со временем скрипты становились всё более и более сложными, поэтому сообщество придумало несколько вариантов организации кода в модули. Появились библиотеки для динамической подгрузки модулей.

AMD – одна из самых старых модульных систем, изначально реализована библиотекой require.js.

CommonJS – модульная система, созданная для сервера Node.js.

UMD – ещё одна модульная система, предлагается как универсальная, совместима с AMD и CommonJS.

Теперь все они постепенно становятся частью истории, хотя их и можно найти в старых скриптах.

Система модулей на уровне языка появилась в стандарте JavaScript в 2015 году и постепенно эволюционировала. На данный момент она поддерживается большинством браузеров и Node.js. Далее мы будем изучать именно её.

Что такое модуль?

Модуль – это просто файл. Один скрипт – это один модуль.

Модули могут загружать друг друга и использовать директивы export и import, чтобы обмениваться функциональностью, вызывать функции одного модуля из другого:

- export отмечает переменные и функции, которые должны быть доступны вне текущего модуля.

- import позволяет импортировать функциональность из других модулей.

Директива import загружает модуль по пути ./sayHi.js относительно текущего файла и записывает экспортированную функцию sayHi в соответствующую переменную.

Так как модули поддерживают ряд специальных ключевых слов, и у них есть ряд особенностей, то необходимо явно сказать браузеру, что скрипт является модулем, при помощи атрибута


написать администратору сайта