ответы. ответы на вопросы. 1. Agile, tdd и bdd
Скачать 182.7 Kb.
|
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), а я приведу тут лишь пример.
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 кода: Jasmine, qUnit и YUI Test. В первую очередь нас интересовало удобство написания тестов, отсутствие привязанности к DOM-модели браузера (на тот случай, если появится модуль для Node.js), поддержка асинхронных тестов и встроенные средства работы с Test Doubles.
Классический синтаксис 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 в соответствующую переменную. Так как модули поддерживают ряд специальных ключевых слов, и у них есть ряд особенностей, то необходимо явно сказать браузеру, что скрипт является модулем, при помощи атрибута |