В этой статье я хочу представить вам новую библиотеку для тестирования AVA. Относительно новую, ей уже больше 2-х лет, и она обзавелась солидным количеством плагинов и конечно же сообществом которое ее развивает. Мы посмотрим на функционал библиотеки. Настроим окружение и напишем пару тестов, чтобы посмотреть на библиотеку в действии.
Что же предлагает AVA?
В первую очередь библиотека предлагает скорость. Тесты запускаются параллельно, что дает ускорение выполнения тестов. В качестве примера приводится проект Pageres, в котором тестирование было перенесено на AVA, что дало увеличение почти в 3 раза(31 секунда было и 11 стало). Тесты не зависят от глобального состояния и от других тестов, что конечно же упрощает тестирование. Из коробки сразу идет использование es2015.
Что нужно сделать чтобы начать пользоваться AVA уже сейчас?
Установить соответствующий npm модуль. Установим как зависимость для работы в конкретной папке.
// package.json
...,
"scripts": {
"test": "ava"
},
...
npm install -D ava
npm test
или глобально
npm i -g ava
ava
Запуск тестов
Настало время написать первый тест, возьмем пример из официального репозитория. И сохранить его как my-tests.js
import test from 'ava';
test('foo', t => {
t.pass();
});
test('bar', async t => {
const bar = Promise.resolve('bar');
t.is(await bar, 'bar');
});
Сразу видим использование es2015 со стрелочными функциями, let и async. На мой взгляд, не обманули и действительно минималистичный синтаксис.
Запускаем тесты
npm test my-tests.js
// or
ava my-tests.js
И получаем результат
2 passed
Если мы хотим увидеть более подробную информацию о каждом тесте, мы можем использовать параметры для модуля
ava my-tests.js --verbose
// or
ava my-tests.js -v
foo
bar
2 tests passed
Так же мы можем запустить watcher, чтобы разрабатывать в стиле TDD
ava my-tests.js --watch
// or
ava my-tests.js -w
Поспотреть полный список параметров можно
ava --help
API библиотеки
Простой тест:
test('description', t => {
});
Одна из самых распространенных ситуаций, когда нужно выполнить только один тест из всех:
test.only('test only', t => {
t.pass();
});
Пропуск теста, может понадобиться при рефакторинге, поиске ошибки:
test.only('test only', t => {
t.fail();
});
Заглушка для теста
Вынесено на уровень API, что очень интересно. Можно сделать напоминалку прямо в тестах.
test.todo('описание');
Если нам нужно протестировать асинхронную часть кода, мы можем воспользоваться "cb":
test.cb('callback', t => {
setTimeout(function() {
console.log('time');
t.end();
}, 3000);
});
Упорядоченное выполнение тестов
Параметр serial, позволит нам выполнять тесты в определенной последовательности. Например, мы хотим проверить существование конфигурационного файла. Если его нет, его нужно создать. Мы сделаем 2 теста, один будет создавать наш файл, а второй проверять.
И нам удобней будет, чтобы они запускались именно последовательно.
import test from 'ava';
import fs from 'fs';
const path = 'serial-test-one.txt';
test.cb('serial 1: create file', t => {
fs.writeFile(path, 'test', function(err) {
if (err) {
t.fail();
} else {
t.pass();
}
t.end();
});
});
test.cb('serial 2: is file exists', t => {
fs.access(path, fs.F_OK, function(err) {
if (err) {
t.fail();
} else {
t.pass();
}
t.end();
});
});
Написав такой код мы получаем
serial-one › serial 2
serial-one › serial 1
2 tests passed
И видим, что тесты запустились и закончились успешно. Но это не правильно, данных код не гарантирует выполнение в нужным нам порядке. Если мы сымитируем ситуацию когда файла еще нет, skip-ем тест создания, мы получим ошибку
- serial-one › serial 1
serial-one › serial 2 Test failed via t.fail()
1 test failed
1 test skipped
1. serial-one › serial 2
AssertionError: Test failed via t.fail()
serial-one.js:19:9
FSReqWrap.oncomplete (fs.js:123:15)
Чтобы гарантировать последовательность мы можем использовать параметр --serial или -s
ava serial-one.js -s
serial-one › serial 1
serial-one › serial 2
2 tests passed
Или использовать
test.cb.serial('serial 1', t => {
...
});
Тест падает и мы об этом знаем. Мы можем об этом явно указать.
test.failing('failing', t => {
t.fail();
});
В результате видим, что этот тест падает, но мы знаем об этом, и в идеале уже, что то делаем.
1 known failure
Очень приятно, что мы можем совмещать параметры. Это позволяет нам реализовать любой сложности тесты и запускать в только необходимые и в нужном порядке.
test.only.cb
test.cb.only
Before и After
Для настройки окружения тестов есть before и after. Они будет выполнены один раз на старте выполнения тестов и в конце соответственно.
test.before(t => {
});
test.after(t => {
});
Так же мы можем объявить несколько таких функций и они будет вызываться в порядке добавления
test.before(t => {
console.log('before');
});
test.before(t => {
console.log('before#2');
});
before
before#2
Работает и для after.
Если текст падает, after не вызываются. Чтобы исправить ситуацию нужно использовать модификатор always.
test.after.always(t => {
});
beforeEach и afterEach
Когда нам нужно настраивать окружение перед каждый тестом используем beforeEach и afterEach.
test.beforeEach(t => {
});
test.afterEach(t => {
});
Для них сохраняется поведение как и для before и after: порядок объявления и при ошибке в тесте after не вызываются(если нет always).
Assertions
test('test', t => {
t.pass();
t.skip.fail();
t.truthy(true);
t.truthy('unicorn');
t.falsy(false);
t.falsy(1 === 0);
t.true(true);
t.false(false);
t.is(1, 1);
t.not(1, 0);
t.deepEqual([0, 1, 2], [0, 1, 2]);
t.notDeepEqual([0, 2, 2], [0, 1, 2]);
});
Очень удобный deepEqual, и возможность пропустить проверку.
Отдельно рассмотрим вывод ошибок, он очень детальный.
test(t => {
const a = /foo/;
const b = 'bar';
const c = 'baz';
t.true(a.test(b) || b === c);
});
t.true(a.test(b) || b === c)
| | | |
| "bar" "bar" "baz"
false
Что безусловно помогает отладке.
Плагины
До знакомства с AVA, я писал тесты на Jasmine. Мне нравится Behavior-Driven style. Для этого в AVA есть плагин ava-spec.
npm i -D ava-spec
После чего мы можем писать тесты так
import {describe} from 'ava-spec';
describe('module#1', it => {
it('can look almost like jasmine', t => {
t.deepEqual([1, 2], [1, 2]);
});
it.todo('todo');
it.skip('fail', t => {
t.fail();
});
});
TAP — Test Anything Protocol
Мы можем кастомизировать информацию о наших тестах. Мне понравился tap-summary.
npm i -D tap-summary
Используем
ava ava-spec.js -t | tap-summary
Реальные модули для тестирования
Сделаем функция, положим ее в отдельный файл, подключим и протестируем.
// ./test/sum.spec.js
import { describe } from 'ava-spec';
import sum from '../src/sum';
describe('sum', it => {
it('should return 10', t => {
const expected = 10;
const actual = sum(3, 7);
t.is(actual, expected);
});
});
// ./src/sum.js
function sum(x, y) {
return x + y;
}
module.exports = sum;
ava test/sum.spec.js
Все работает, наш код из файла подключен и протестирован. Но есть проблема, наш код написал на ES5, а тесты ES6. Давайте исправим эту ситуацию. AVA из коробки использует Babeljs. И для нашего кода мы будет тоже использовать его. Настраиваем конфиги.
// .babelrc
{
"presets": [
"es2015"
]
}
и для AVA. Конфиг AVA находится прямо в package.json.
// ./package.json
...,
"ava": {
"babel": "inherit",
"require": [
"babel-register"
]
},
...
Запускаем без изменений.
ava test/sum.spec.js
Итог
AVA предоставляет отличную платформу для разработки тестов. В этой библиотеке есть все для этого: минималистичный стиль, быстрое выполнение, гибкость написания тестов, работа с тестами и окружением для них, информативный вывод ошибок. В сумме с возможностью кастомизировать как сам код тестов, исходя из предпочтений и необходимости, так и вывод информации по тестам.
Об авторе библиотеки
Хотелось бы чуть чуть рассказать про автора этой библиотеки. Это, наверное, один из самых известных в JS сообществе людей Синдре Сорхус. На его странице на github вы можете посмотреть на его проекты и в клад в сообщество. И/или вы можете познакомиться с ним как с человеком, на сколько это возможно в интернете, или задать вопрос/ы через ama — Ask me anything!.
P.S.
- В полезных ссылках последний репозиторий с примерами для статьи.
- От себя: после знакомства с AVA, я перешел в своих новых домашних проектах на AVA. Следующий рабочий проект будет разрабатываться с этой библиотекой. Возможно некоторые старые свои проекты переведу на AVA заодно замерю скорость выполнения и сложность перехода.
Полезные ссылки:
- AVA repo
- awesome-ava много полезной информации о AVA: статьи, видео, плагины и туториалы.
- awesome-tap — все о TAP — Test Anything Protocol
- Examples
Комментарии (20)
776166
24.10.2016 19:59+2От какого слова происходит в названии «футурестическая»?
alekseyleshko
24.10.2016 21:26+1Спасибо, исправил! Я честно старался. Вычитывал. Но совсем забыл про название.
justboris
25.10.2016 12:19+5User experience у инструмента не очень. На первый взгляд все красиво, ES6, async и тому подобные прелести.
А потом выясняется, что есть баг в такой базовой вещи, как test.only и доверие к иструменту падает.
Та же ситуация и в коммьюнити. Люди, два года назад хвалившие AVA, сейчас мигрируют на Jest и нахваливают его не меньше.
И, наконец, сам автор AVA говорит, что библиотека не расчитана на тестирование UI-компонентов и была изначальна предназначена для тестирования node.js-модулей, которых у него великое множество.
Следует учитывать эти моменты при выборе библиотеки для тестирования своего проекта
mwizard
И в чем разница с Mocha, кроме названия?
Vovchikvoin
Я лично не юзал AVA, но как понял из статьи, отличие от мочи — свой assertion, никаких chai; из коробки ES6;
alekseyleshko
AVA это основа. Минимум всего(но хватает для работы), ES6, параллельный запуск тестов и изоляцией.
Про assertion, на текущий момент я так понял, что только базовые. И это будет либо расширятся, либо уже сейчас можно сделать свою версию ava-assert.
Mocha с 2011 года, AVA всего 2. Надо подождать развития и посмотреть, что будет предложено сообществом.
Но на мой взгляд достойный конкурент.
alekseyleshko
На мой взгляд, сейчас тенденция делать параллельно все в окружении в JS: gulp пришел на место grunt, yarn заявляет права на пакетный менеджер npm.
Поэтому это вроде как логичное развитие событий. Основное что дает AVA это скорость выполнение тестов. Это довольно важно. А на каких то проектах может быть и критично.
На мой взгляд пример Pageres от 31 секунд до 11 это хорошо. Но показательные будет уже большой коммерческий проект, так что ждем.
Кастомизация assertion возможна в AVA. Но базовый API assertion довольно маленький, но покрывает основные потребности.
И да ES6 из коробки, просто факт что уже пора использовать.
webschik
Если говорить о скорости и параллельном выполнении, мне очень нравится Jest. Сравнивали с AVA?
alekseyleshko
Jest, честно сказать впервые слышу, но обязательно посмотрю подробнее.
Бегло пробежался, это facebook разработчики(отсылка к yarn). Jest с AVA очень похожи на между собой.
API и assertion, что то близкое к jasmine. Mock-и из коробки, очень интересно.
У Jest по понятным причинам сразу тестирование React-а в примерах, у AVA тоже. Оба используют enzyme.
Была идея сравнить по скорости AVA с Mocha и Jasmine, но там вроде как заведомо не равный бой.
А тут прям брат близнец, причем оба проекта начались в 2014 году с разницей в полгода.
Может быть стоит все таки сделать какой то сравнение/срез. Может быть будет интересно. Хотя даже если они будет почти идентичны, все равно будет интересно.
webschik
Jest внутри использует Jasmine, но API позволяет использовать другой движок. Я узнал о Jest, когда начал разработку на React Native, но сейчас использую и в других проектах, без привязки к React.
На одном рабочем проекте мигрировали на Jest с Karma + Jasmine, именно из-за производительности.
Сейчас такая картина для unit-тестов:
Кстати, у них есть раздел для пользователей AVA и Tape :)
alekseyleshko
Понял, я почитал тоже немного о нем чуть-чуть больше узнал о нем.
На мой взгляд у Вас достойный результат по тестированию. А мигрировали с чего? И там какой показатель был?
Легкость переходана новую либу тестирование это важно, особено при миграции.
У Jest более живое сообщество, как я посмотрю. Но он и на полгода старше. AVA имеет хорошие показатели интереса.
webschik
Раньше в проекте unit-тесты запускались на Karma.js и написаны были на Jasmine. Эдакая устоявшаяся классика :)
К сожалению не помню результатов на старой связке, перешли примерно полгода назад, результаты были ужасными, как по мне, что-то около 2х минут.
alekseyleshko
Люблю эту(jasmine + karma) связку, тоже часто использовал.
Понял, результат отличный.
Odrin
В чем заключается это «ES6 из коробки»? Какое отношение библиотека имеет к es? Они же не тащат вместе с собой отдельный интерпретатор.
alekseyleshko
Либа с зависимостях ташит как раз Babeljs, что как раз позволяет писать тесты на ES6. Чтобы писать код в es6 и его тестировать, сам код модулей надо обрабатывать. В статье простой способ это сделать.