Итак, потребовалось реализовать юнит-тестирование для 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');
Что получается, можно посмотреть здесь. Можно посмотреть на отчет и увидеть, что наш сложный пример не полностью покрыт тестами, пропущена одна ветка и ее надо срочно покрыть тестами.