[Из песочницы] AVA — Футуристическая JavaScript библиотека для тестирования
В этой статье я хочу представить вам новую библиотеку для тестирования 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
Комментарии (11)
24 октября 2016 в 18:58
+1↑
↓
И в чем разница с Mocha, кроме названия?24 октября 2016 в 21:27
0↑
↓
Я лично не юзал AVA, но как понял из статьи, отличие от мочи — свой assertion, никаких chai; из коробки ES6;24 октября 2016 в 22:03
0↑
↓
AVA это основа. Минимум всего (но хватает для работы), ES6, параллельный запуск тестов и изоляцией.
Про assertion, на текущий момент я так понял, что только базовые. И это будет либо расширятся, либо уже сейчас можно сделать свою версию ava-assert.Mocha с 2011 года, AVA всего 2. Надо подождать развития и посмотреть, что будет предложено сообществом.
Но на мой взгляд достойный конкурент.
24 октября 2016 в 21:39
0↑
↓
На мой взгляд, сейчас тенденция делать параллельно все в окружении в JS: gulp пришел на место grunt, yarn заявляет права на пакетный менеджер npm.
Поэтому это вроде как логичное развитие событий. Основное что дает AVA это скорость выполнение тестов. Это довольно важно. А на каких то проектах может быть и критично.
На мой взгляд пример Pageres от 31 секунд до 11 это хорошо. Но показательные будет уже большой коммерческий проект, так что ждем.Кастомизация assertion возможна в AVA. Но базовый API assertion довольно маленький, но покрывает основные потребности.
И да ES6 из коробки, просто факт что уже пора использовать.
24 октября 2016 в 23:12
0↑
↓
Если говорить о скорости и параллельном выполнении, мне очень нравится Jest. Сравнивали с AVA?24 октября 2016 в 23:59
0↑
↓
Jest, честно сказать впервые слышу, но обязательно посмотрю подробнее.
Бегло пробежался, это facebook разработчики (отсылка к yarn). Jest с AVA очень похожи на между собой.
API и assertion, что то близкое к jasmine. Mock-и из коробки, очень интересно.У Jest по понятным причинам сразу тестирование React-а в примерах, у AVA тоже. Оба используют enzyme.
Была идея сравнить по скорости AVA с Mocha и Jasmine, но там вроде как заведомо не равный бой.
А тут прям брат близнец, причем оба проекта начались в 2014 году с разницей в полгода.
Может быть стоит все таки сделать какой то сравнение/срез. Может быть будет интересно. Хотя даже если они будет почти идентичны, все равно будет интересно.
24 октября 2016 в 19:59
+2↑
↓
От какого слова происходит в названии «футурестическая»?24 октября 2016 в 20:03
–1↑
↓
Лучше не спрашивайте — кошмары сниться будут)))24 октября 2016 в 21:26
+1↑
↓
Спасибо, исправил! Я честно старался. Вычитывал. Но совсем забыл про название.
24 октября 2016 в 21:26
0↑
↓
«Футурестическая» — это опечатка или хитрый каламбур?24 октября 2016 в 21:27
0↑
↓
Ох если бы. Спасибо, исправил.