Итак, потребовалось реализовать юнит-тестирование для JS-кода. В качестве среды для выполнения и фреймворка для написания тестов был выбран js-test-driver. Причины таковы:
- есть в виде плагина для применяемой командой IDE — PhpStorm (к сожалению в настоящий момент плагин не работает на текущей платформе PhpStorm, о чем есть соответствующий тикет в статусе Started)
- умеет выполнять тесты автоматически в нескольких браузерах
- работает из командной строки, просто встроить в CI
- умеет давать отчеты о code coverage
Несмотря на то что плагин для IDE сейчас неработоспособен, «пощупать» технологию можно из консоли. Сервер и среда исполнения запускаются отдельно из консоли и могут гонять тесты «в ручном режиме» по пинку пользователя.
Попробуем в деле
Код, который будем тестировать
var greeter = function(toSay){ this.whatToSay = toSay; } greeter.prototype.say = function(sayBye){ if(sayBye == true) return "Goodbye " + this.whatToSay; else return "Hello " + this.whatToSay; }
И тест
var testCase = new TestCase("Say"); testCase.prototype.testCase1 = function(){ var i = new greeter('test'); assertEquals("Hello test", i.say(false)); };
Файловая структура
\jstd \plugins coverage.jar code.js test.js conf jstestdriver.jar
Конфигурация для запуска (файл conf в формате YAML)
load: - code.js - test.js server: http://localhost:4224
Запускаем
Сперва стартуем сервер
H:\jstd>java -jar jstestdriver.jar --port 4224
Запускаем браузер, идем на localhost:4224, овладеваем браузером. Запускаем прогон тестов.
UPD: подключить к тестированию можно произвольное количество произвольных браузеров. Можно даже подключиться с удаленной машины из-под другой ОС. Подключение браузера к тестированию == открытие страницы на неком сервере (который в данном случае — вам сервер js-test-driver)
H:\jstd>java -jar JsTestDriver.jar --config conf --tests all .. Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (1,00 ms) Chrome 6.0.472.63 Windows: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (1,00 ms) Safari 525.28.1 Windows: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (1,00 ms)
Видим, что прогнали всего 2 теста. В т.ч. в браузере Chrome — 1, и он прошел успешно, в браузере Safari — также 1 и также успешно. Все замечательно.
А что там было насчет code coverage?
CodeCoverage подключается отдельным плагином. Данные о покрытии могут либо отображаться в виде статической информации (файл такой-то покрыт на N%) по окончании исполнения тестов, либо могут выгружаться в файл формата LCOV. Авторы предлагают генерировать визуальные отчеты с помощью тулзы genhtml. Беглый поиск портированных под Win32 результатов не дал, поднимать Cygwin или отдельную машину для построения отчетов не хочется...
Запустим тесты с code coverage
Подключим плагин. Отредактируем конфигурационный файл (conf).
load: - code.js - test.js server: http://localhost:4224 plugin: - name: "coverage" jar: "plugins/coverage.jar" module: "com.google.jstestdriver.coverage.CoverageModule"
Запустим тесты
H:\jstd>java -jar JsTestDriver.jar --config conf --tests all Safari: Runner reset. .Safari: Runner reset. Chrome: Runner reset. .Chrome: Runner reset. Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (1,00 ms) Chrome 6.0.472.63 Windows: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (1,00 ms) Safari 525.28.1 Windows: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (0,00 ms) H:/jstd/code.js: 83.33333% covered H:/jstd/test.js: 100.0% covered
Видим, что дополнительно к результатам появилась информация о покрытии кода. От такого отчета толку чуть более чем никакого. Начнем сохранять результаты тестов в файл.
H:\jstd>java -jar JsTestDriver.jar --config conf --tests all --testOutput ./out Safari: Runner reset. .Safari: Runner reset. Chrome: Runner reset. .Chrome: Runner reset. Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (1,00 ms) Chrome 6.0.472.63 Windows: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (1,00 ms) Safari 525.28.1 Windows: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (1,00 ms)
Теперь информации о покрытии не видно совсем, но в папке ./out появился файл с покрытием в формате LCOV.
Формат LCOV
Формат lcov-файла, генерируемого js-test-driver предельно прост.
SF:H:/jstd/code.js DA:1,2 DA:2,2 DA:5,2 DA:6,2 DA:7,0 DA:9,2 end_of_record SF:H:/jstd/test.js DA:1,2 DA:3,2 DA:4,2 DA:5,2 end_of_record
SF — файл, для которого приводятся данне далее, DA — данные о покрытии (DA: Строка, СколькоРазВыполнена).
Генерируем красивый отчет: PHP_CodeCoverage
PHPUnit — фреймворк дле реализации юнит-тестирования для PHP, имеет возможность генерировать отчеты о code coverage. Модуль, занимающийся CodeCoverage, очень легко отделяем и очень аккуратно реализован. В состав входит интерфейс PHP_CodeCoverage_Driver, классы, имплементирующие его, могут служить источником данных о Code coverage для прочих компонентов проекта (построитель отчетов в т.ч.).
Xdebug. Как он отдает данные о покрытии?
Для файла...
<?php xdebug_start_code_coverage(); function a() { $x = 10; } $b = 30; var_dump(xdebug_get_code_coverage());
Получим результат...
array( 'Z:\home\test\www\test.php' => array( 4 => 1 8 => 1 10 => 1 ) );
Видно что форматы очень похожи, можно сделать свой драйвер
Ниже — простой пример кода, генерирующего отчет о покрытии. Предполагается, что данные о покрытии находятся в файле coverage.dat. Отчет будет расположен в папке CodeCoverageReport.
<?php include('PHP/CodeCoverage.php'); include('PHP/CodeCoverage/Driver/Lcov.php'); include('PHP/CodeCoverage/Report/HTML.php'); // ./lcov_coverage.dat contains ine coverage report in LCOV format $coverage = new PHP_CodeCoverage(new PHP_CodeCoverage_Driver_Lcov('./coverage.dat')); $coverage->start('mytest'); $coverage->stop(); $writer = new PHP_CodeCoverage_Report_HTML(); $writer->process($coverage, 'CodeCoverageReport');
Что получается, можно посмотреть здесь. Можно посмотреть на отчет и увидеть, что наш сложный пример не полностью покрыт тестами, пропущена одна ветка и ее надо срочно покрыть тестами.
