Предупреждение: эта статья в основном посвящена техническому искусству и ремеслу.
Я хочу вывести в офисе экран с последними результатами модульного тестирования, например, доску объявлений, чтобы вся команда могла видеть статус теста - и мы не пропустим неудачные тесты.
Мы используем Mocha для запуска модульных тестов в Node (nodejs). Дженкинс наблюдает за нашим репозиторием git и запускает тесты, когда мы вводим новый код.
Конечный продукт (github и пакет npm) просматривается в браузере, автоматически обновляется и выглядит примерно так:
Введение
С M ocha мы можем запустить $ mocha ./src/**/*.test.js
для создания консольного отчета, который выглядит примерно так:
Но знаете ли вы, что с помощью репортера можно выводить результаты тестов в любом формате? Mocha даже предоставляет множество примеров / забавных репортеров.
Мы можем использовать:
mocha ./src/**/*.test.js --reporter <reporterName>
флаг --reporter
позволяет нам использовать настраиваемый репортер.
Один файл или пакет?
Написание собственного настраиваемого репортера может быть таким же простым, как создание одного файла Javascript в существующем проекте и ссылки на него с помощью флага -reporter
.
Для демонстрации Mocha предоставляет пример кода настраиваемого репортера, который мы можем сохранить в корне нашего проекта и ссылаться на него, например: mocha ./src/**/*.test.js -reporter reporter.js
В качестве альтернативы вы можете заключить репортера в пакет для использования в другом месте. Это немного выходит за рамки данной статьи, однако я должен упомянуть, что у меня были проблемы с mocha, не распознающим локальные пакеты.
Начиная
Пример кода на самом деле работает довольно хорошо и очень прост. Мы просто экспортируем одну функцию (или репортера), которой передается объект бегун, предоставляющий некоторые события, к которым мы можем подключиться.
# Example code from Mocha - we just export this one function module.exports = MyReporter; function MyReporter(runner) { ... }
Наш пользовательский репортер будет иметь следующий формат:
function MyReporter(runner) { // 1. Store intermediate values // to be inserted into the HTML template later // 2. Update these values when tests run, pass or fail. // 3. When the runner ends, update the HTML file }
Окончательный результат можно увидеть в apb-mocha-reporter / src / apbmochareporter.js на github.
Расчет значений, которые мы хотим отобразить
На основе примера кода я начал с написания перехватчиков для событий прошел и не прошел, суммировав количество тестов в каждой категории, чтобы получить значения, которые мы вставим в наш HTML. Позже я обнаружил, что эти значения уже подсчитаны для меня runner.stats
, поэтому я воспользуюсь этим.
Однако я также хочу выводить подробные результаты тестов в формате JSON, поэтому мне все равно нужно написать несколько ловушек. Я начинаю с объявления некоторых массивов с ограниченной областью действия для хранения результатов тестирования, а затем вставляю в эти массивы всякий раз, когда срабатывает перехватчик событий. Вот пример ловушки для проверки «пройден»:
var json_passes = []; runner.on('pass', function(test){ json_passes.push(test); update() // print to the console. });
Теперь у нас есть полный контроль над выводом - давайте отформатируем его как HTML.
Вывод HTML - шаблонизатор в 12 строк кода.
Программная генерация или создание HTML - это не ракетостроение. Типичный подход:
- Создайте шаблон HTML, близкий к тому, что вы хотите.
- Определите переменные части шаблона, которые вы хотите изменить.
- Напишите свой код, чтобы получить запасные части.
- Используйте механизм шаблонов, чтобы загрузить HTML и заменить переменные запасными частями.
Существует множество движков для создания шаблонов. Усы едины. Handlebars, doT и EJS тоже делают свою работу. Все они в основном работают одинаково, но все они представляют собой дополнительную зависимость, которая нам не нужна. Мы не делаем здесь ничего сложного, и я бы предпочел оставить этот пакет без зависимостей. Так что строим сами.
Замена Regex
Регулярные выражения (regex) - это замечательная, мощная и сложная концепция, которую я не буду вдаваться в подробности. Регулярные выражения не уникальны для Javascript, и даже в JS существует несколько способов их использования. В нашем случае мы воспользуемся методом string.replace()
. (Полная документация здесь)
str.replace(regexp|substr, newSubstr|function)
Мы собираемся взять строку с именем template
и найти все вхождения слов, заключенных в двойные волнистые скобки, например: {{word}}
. Затем мы собираемся заменить это слово созданным нами значением - в данном случае результатом нашего теста.
Например, предположим, что мы вычислили процент успешно выполненных тестов как: run_percent
, и в нашем шаблоне мы написали {{run_percent}}
. Мы могли бы написать: template.replace(/{{run_precent}}/g, run_percent)
Литерал регулярного выражения окружен косой чертой. Буква g означает поиск по всему миру.
Но мы можем добиться большего. Мы можем найти любое слово, окруженное волнистыми линиями, с помощью следующего регулярного выражения: /{{.*?}}/g
.
означает любой символ, кроме новой строки.*
означает соответствие предыдущему элементу 0 или более раз.?
означает, что предыдущий элемент должен быть «нежадным», т.е. Самый короткий матч.
Наконец, мы не собираемся просто заменять каждую работу в волнистых линиях одним значением. Если мы передадим функцию replace()
в качестве второго параметра, мы сможем стать намного умнее ...
let newContent = template.replace(/{{.*?}}/g, function(match){ return replacements[match] })
Здесь Match
- это слово, которое находит регулярное выражение. replacements
- это объект с ключами для каждой из переменных нашего шаблона (волнистые линии) и значениями того, чем мы хотим их заменить. Вот пример:
// Example of replacements object { "{{lastrun_date}}": new Date(), "{{run_percent}}": run_percent, "{{run_numerator}}": sum, "{{run_denominator}}": total }
Мы завершаем все это с помощью кода чтения / записи файла в небольшой красивой функции, называемой updateBillboard
, и у нас есть механизм создания шаблонов в 12 строках Javascript.
Наконец, функция updateBillboard
вызывается из события runners end
.
Обработка аргументов командной строки
Я хочу, чтобы пользователь мог контролировать работу репортера. Самый простой пример - запретить вывод в консоль.
Mocha предоставляет основной способ передачи аргументов командной строки репортеру через флаг —-reporter-options
. Этот вариант плохо документирован - в основной документации только сказано:
Usage: mocha [debug] [options] [files]
Options:
...
-O, --reporter-options <k=v,k2=v2,...> reporter-specific options
...
Это означает, что мы можем использовать либо -O
, либо —- reporter-options
, за которым следует список параметров, разделенных запятыми (без пробелов!). У каждой опции может быть значение, указанное после знака равенства. Это значение не является обязательным.
Что нигде не описано (кроме примера кода), так это то, как reporter-options
передаются репортеру:
function MyReporter(runner, options) { const SILENT = options.reporterOptions.silent ... }
Второй параметр параметров передается в функцию-репортер как объект, содержащий объект reporterOptions
, который содержит каждый параметр и его значение.
Пример:
// Test command mocha ./**.test.js --reporter MyReporter --reporter-options silent,savejson=example
Предоставляет нам следующее в нашем пользовательском репортере:
// console.log(options) inside MyReporter() { reporterOptions: { silent: true, savejson: 'example' }, globals: [], files: [] }
Если значение не указано (например, для silent
), по умолчанию используется логическое значение true
.
Использование аргумента командной строки для предотвращения журналов
Чтобы контролировать, когда появляются журналы, мы сохраним значение параметра silent
и напишем простую функцию журналирования, чтобы проверить его:
const SILENT = options.reporterOptions.silent function write(str){ if(!SILENT) process.stdout.write(str); }
Теперь мы заменяем все журналы на write (), и когда передается опция silent
, ничего не происходит!
Я использую
process.stdout.write(str);
, поэтому могу вручную обрабатывать новые строки (\n
) и символы возврата каретки (\r
) для перезаписи предыдущего вывода.
Вывод
И вуаля!
Статус нашего теста отображается где-то в типично унылой офисной среде. Поддельный завод и все такое.
Я быстро поискал существующие плагины jenkins / репортеры мокко, но не нашел ничего на 100% подходящего. К тому же это было весело.
Пакет еще не полностью готов. Наиболее заметным упущением являются (по иронии судьбы) юнит-тесты. Я готовлюсь к своей докторской диссертации через пару недель, так что надеюсь, что найду их позже.
Если у вас есть предложения по функциям, дайте мне знать на github!
Я Эйдан Брин, и я руковожу консалтингом по программному обеспечению в Дублине, Ирландия. Если вам понравился этот пост, подумайте о том, чтобы подписаться на меня в твиттере или подписаться на мой личный список рассылки для получения обновлений реже, чем раз в месяц.