Примечание от переводчика
Здесь содержится перевод файла readme.md. Если при нажатии на ссылку, содержащую последние правки в master ветке AVA, Вы не можете найти файл readme.md
, то можете считать что перевод актуален.
Футуристичный инструмент для тестирования
Даже с учетом того, что JavaScript выполняется в одном потоке, IO в Node.js могут происходить параллельно в связи с природой самого Node.js. AVA в полной мере пользуется этим преимуществом и запускает Ваши тесты одновременно, что особенно важно при серьезных IO в тестах. Кроме того, тестовые файлы запускаются параллельно в разных процессах, предоставляя большую производительность и изолированное окружение для каждого тестового файла. Переход с Mocha на AVA в Pageres улучшил время тестирования с 31 секунды до 11 секунд. Возможность запускать тесты одновременно, заставляет Вас писать тесты, в которых нет необходимости зависеть от глобального состояния или состояний других тестов, что поистине круто!
Прочтите наш гайд участника если вы хотите внести вклад в проект(проблемы/пулл реквесты/etc).
Подпишитесь на Твиттер аккаунт AVA для отслеживания обновлений.
Переводы: Español, Français, Italiano, 日本語, Português
- Использование
- Командная строка
- Конфигурация
- Документация
- API
- Проверки
- Советы
- FAQ
- Рецепты
- Поддержка
- Похожее
- Ссылки
- Команда
- Минимально и быстро
- Простой синтаксис тестов
- Запуск тестов параллельно
- Атомарные операции в тестах
- Нет неявных глобальных переменных
- Изолированное окружение для каждого теста
- Поддержка ES2015
- Поддержка Promises
- Поддержка генераторов
- Поддержка асинхронных функций
- Поддержка Observable типов
- Поддержка коллбеков
- Улучшенные проверки
- Опциональный TAP вывод
- Чистый Stack trace
import test from 'ava';
test(t => {
t.deepEqual([1, 2], [1, 2]);
});
Установите AVA глобально и запустите с флагом --init
, чтобы добавить AVA в Ваш package.json
файл.
$ npm install --global ava
$ ava --init
{
"name": "awesome-package",
"scripts": {
"test": "ava"
},
"devDependencies": {
"ava": "^0.11.0"
}
}
Любые аргументы, переданные после --init
будут добавлены в package.json
файл.
Вы также можете установить AVA в текущий каталог модулей:
$ npm install --save-dev ava
Вам необходимо настроить test
скрипт в Вашем package.json
файле для использования ava
(смотрите ниже).
Создайте тестовый файл test.js
в корневом каталоге Вашего проекта:
import test from 'ava';
test('foo', t => {
t.pass();
});
test('bar', async t => {
const bar = Promise.resolve('bar');
t.is(await bar, 'bar');
});
$ npm test
$ npm test -- --watch
В AVA есть интеллектуальный режим наблюдения. Подробнее в этом рецепте.
$ ava --help
Usage
ava [<file|directory|glob> ...]
Options
--init Add AVA to your project
--fail-fast Stop after first test failure
--serial, -s Run tests serially
--require, -r Module to preload (Can be repeated)
--tap, -t Generate TAP output
--verbose, -v Enable verbose output
--no-cache Disable the transpiler cache
--match, -m Only run tests with matching title (Can be repeated)
--source, -S Pattern to match source files so tests can be re-run (Can be repeated)
Examples
ava
ava test.js test2.js
ava test-*.js
ava test
ava --init
ava --init foo.js
Default patterns when no arguments:
test.js test-*.js test/**/*.js
Замечание - командная утилита AVA CLI будет использовать локальную установку AVA, даже при запуске глобальной команды ava
.
Каталоги по умолчанию рекурсивны, все *.js
файлы в них будут считаться тестовыми. Каталоги с названием fixtures
, helpers
и node_modules
игнорируются, также как и те, что начинаются с _
. Это весьма полезно, если Ваши вспомогательные файлы находятся в том же каталоге, что и тестовые файлы.
Когда используется команда npm test
, Вы можете передать дополнительные аргументы npm test test2.js
, но флаги должны быть переданы вот так - npm test -- --verbose
.
Все опции командной строки также могут быть установлены в секции ava
вашего package.json
файла. Это позволяет изменять стандартное поведение команды ava
, так что Вам не нужно постоянно писать одни и те же опции в командной строке.
{
"ava": {
"files": [
"my-test-folder/*.js",
"!**/not-this-file.js"
],
"source": [
"**/*.{js,jsx}",
"!dist/**/*"
],
"match": [
"*oo",
"!foo"
],
"failFast": true,
"serial": true,
"tap": true,
"verbose": true,
"require": [
"babel-register"
],
"babel": "inherit"
}
}
Аргументы переданные в командную строку всегда будут иметь приоритет перед конфигурацией в package.json
файле.
Смотрите секцию Поддержка ES2015 для пояснений по опции babel
.
Тесты выполняются одновременно. Ваши тесты могут быть и асинхронными, и синхронными. Тесты, которые не возвращают promise
или observable
, считаются синхронными.
Мы настойчиво рекомендуем использовать асинхронные функции; Они делают асинхронный код кратким и читабельным, неявно возвращая Promise.
При использовании Promise
или observable
, Вы можете включить "коллбек мод" следующим образом: test.cb([title], fn)
. Все тесты, которые написаны с "коллбек модом" должны заканчиваться вызовом t.end()
. Этот режим в основном предназначен для тестирования API в коллбек стиле.
Вы должны сделать все тесты синхронными. Они не могут быть описаны внутри setTimeout
, setImmediate
и т.д.
Все тестовые файлы запускаются из текущего каталога, так что process.cwd()
тот же, что и __dirname
. Вы можете использовать относительные пути вместо path.join(__dirname, 'relative/path')
.
Для создания теста Вам необходимо импортировать AVA Api и вызвать функцию test
. Заголовок теста является не обязательным и Вы можете его пропустить, тест-функция обязательна. Тест-функция будет вызвана во время запуска тест.
Тест-функция получает выполняемый объект первым аргументом. Согласно соглашению этот аргумент называется t
.
import test from 'ava';
test('my passing test', t => {
t.pass();
});
Заголовки теста - не обязательны и Вы можете писать тесты без заголовка:
test(t => {
t.pass();
});
Рекомендуем указывать заголовки тестов, если у Вас больше одного теста.
Если Вы не указали заголовок теста, но передали именную функцию, то имя функции будет использоваться как заголовок:
test(function name(t) {
t.pass();
});
План проверок необходим для того, чтобы убедиться, что заданное количество проверок будет выполнено. В большинстве случаев, он гарантирует, что тест не прервется до того, как ожидаемое количество проверок выполнится. План может провалить тест, если будет выполнено большее число проверок - это удобно, если проверки выполняются в коллбеке или цикле.
Помните, что в отличие от node-tap/tape
, AVA автоматически не завершит тест после достижения ожидаемого количества проверок.
В этом примере тест завершится успешно:
test(t => {
t.plan(1);
return Promise.resolve(3).then(n => {
t.is(n, 3);
});
});
test.cb(t => {
t.plan(1);
someAsyncFunction(() => {
t.pass();
t.end();
});
});
В этом примере тест завершится ошибкой:
test(t => {
t.plan(2);
for (let i = 0; i < 3; i++) {
t.true(i < 3);
}
}); // ошибка, будет выполнено 3 сравнения, что не соответствует .plan(2)
test(t => {
t.plan(1);
someAsyncFunction(() => {
t.pass();
});
}); // ошибка, синхронный тест завершится до сравнения
Конкурентность - это прекрасно, но есть некоторые вещи, которые не могут выполняться одновременно.
В редких случаях, Вы можете использовать test.serial
, для запуска тестов последовательно, один за другим.
test.serial(t => {
t.pass();
});
Обратите внимание, что это применимо только для конкретного тестового файла. AVA запустит все тестовые файлы одновременно, если Вы не передадите --serial
CLI флаг.
Во время разработки может появится необходимость вызвать только определённые тесты. Вы можете использовать .only
модификатор для достижения этих целей.
test('will not be run', t => {
t.fail();
});
test.only('will be run', t => {
t.pass();
});
.only
применяется для всех тестовых файлов. Так что, если Вы используете его в одном файле, то тесты из других файлов не будут запущены.
Флаг --match
позволяет запускать только те тесты, заголовки которых соответствуют шаблону в флаге. Это работает с помощью шаблона поиска. Шаблоны не чувствительны к регистру. Посмотрите matcher
для подробной информации.
Совпадение заголовков, заканчивающихся на foo
:
$ ava --match='*foo'
Совпадение заголовков, начинающихся с foo
:
$ ava --match='foo*'
Совпадение заголовков, содержищах foo
:
$ ava --match='*foo*'
Совпадение заголовков, которые называются foo
(регистро независимы):
$ ava --match='foo'
Совпадение заголовков, которые не содержат foo
:
$ ava --match='!*foo*'
Совпадение заголовков, начинающихся с foo
и заканчивающихся на bar
:
$ ava --match='foo*bar'
Совпадение заголовков, начинающихся с foo
или заканчивающихся на bar
:
$ ava --match='foo*' --match='*bar'
Обратите внимание, что шаблон соответствия имеет приоритет над .only
модификатором. Только тесты с явными заголовками будут совпадать. Тесты без заголовков или тесты, чьи заголовки происходят от имени коллбек функции будут пропущены в случае использования --match
.
Вот что произойдет при запуске AVA с шаблоном *oo*
для следующих тестов:
test('foo will run', t => {
t.pass();
});
test('moo will also run', t => {
t.pass();
});
test.only('boo will run but not exclusively', t => {
t.pass();
});
// не запуститься, нет заголовка
test(function (t) {
t.fail();
});
// не запуститься, нет явного заголовка
test(function foo(t) {
t.fail();
});
Иногда падающие тесты трудно исправить. Вы можете сказать AVA пропустить эти тесты, используя .skip
модификатор. Пропущенные тесты показываются в выводе, но никогда не выполняются. Для пропуска тестов необходима коллбек функция.
test.skip('will not be run', t => {
t.fail();
});
Todo-tests, так же, как и пропуск тестов(skip-tests), показаны в выводе, но не никогда не выполняются. Они могут быть полезны для планирования будущих тестов. Todo тесты требуют наличия заголовка в тесте, коллбек функцию им передать нельзя.
test.todo('will think about writing this later');
AVA позволяет зарегистрировать хуки, которые будут вызваны до(before) и после(after) Ваших тестов.
test.before()
регистрирует хук, который будет запущен перед первым тестом в Вашем тест-файле. Также test.after()
регистрирует хук, который будет запущен после последнего теста.
test.beforeEach()
регистрирует хук, который будет запущен перед каждым тестом в Вашем тест-файле. Также test.afterEach()
регистрирует хук, который будет запущен после каждого теста.
Хуки принимают необязательный заголовок и коллбек функцию аналогично функции test()
. Заголовок будет выведен, если выполнение хука завершилось ошибкой. В коллбек передается выполняемый объект.
before
хук выполняется до beforeEach
хуков. afterEach
выполняется до after
хуков. Каждая категория хуков выполняется в том порядке, в которым они были объявлены.
test.before(t => {
// выполнится перед всеми тестами
});
test.before(t => {
// выполнится после предыдущего хука, но перед тестами
});
test.after('cleanup', t => {
// выполнится после всех тестов
});
test.beforeEach(t => {
// выполнится перед каждым тестом
});
test.afterEach(t => {
// выполнится после каждого теста
});
test(t => {
// обычный тест
});
Выполнение хуком может быть синхронным и асинхронным, так же как и тесты. Чтобы хук выполнялся асинхронно, возвращайте Promise или observable, используйте асинхронные функции или включите "коллбек мод" через test.cb.before()
, test.cb.beforeEach()
, и т.д.
test.before(async t => {
await promiseFn();
});
test.after(t => {
return new Promise(/* ... */);
});
test.cb.beforeEach(t => {
setTimeout(t.end);
});
test.afterEach.cb(t => {
setTimeout(t.end);
});
Держите в голове, что beforeEach
и afterEach
хуки выполняются "до" и "после" запуска теста и по-умолчанию все тесты запускаются асинхронно. Если Вам необходимо выставить глобальное состояние для каждого теста (отслеживание console.log
к примеру), Вам необходимо запускать тесты последовательно.
Помните, что AVA запускает каждый тест-файл в отдельном процессе. Вы не можете обнулять глобальное состояние в after
-хуке, так как он запускается перед завершением процесса.
Хуки beforeEach
и afterEach
могут делить context с тестом:
test.beforeEach(t => {
t.context.data = generateUniqueData();
});
test(t => {
t.is(t.context.data + 'bar', 'foobar');
});
Context по умолчанию - объект, но также он может быть определен:
test.beforeEach(t => {
t.context = 'unicorn';
});
test(t => {
t.is(t.context, 'unicorn');
});
Расшаривание контекста не доступно before
и after
хукам.
Вы можете использовать .serial
, .only
и .skip
модификаторы в любом порядке с любым из - test
, before
, after
, beforeEach
и afterEach
. Для примера:
test.before.skip(...);
test.skip.after(...);
test.serial.only(...);
test.only.serial(...);
Это значит, что Вы можете временно добавить .skip
или .only
в конец Вашего объявления теста или хук без внесения дополнительных изменений.
Вы можете использовать любую библиотеку проверок вместо или с тем функционалом, что встроен в AVA, но в этом случае Вы не сможете использовать метод .plan()
, смотрите #25.
import assert from 'assert';
test(t => {
assert(true);
});
AVA поддерживает модули ES2015 через Babel 6. Просто пишите свои тесты в ES2015. Никакой дополнительной настройки не нужно. Вы можете использовать любую версию Babel в своем проекте. Мы используем наш собственный собранный Babel с предустановками (пресетами) es2015
, stage-2
и плагинами espower
, transform-runtime
.
Пример стандартного babel
конфиг-файла, который использует AVA:
{
"presets": [
"es2015",
"stage-0",
],
"plugins": [
"espower",
"transform-runtime"
]
}
При необходимости вы можете внести изменение в поведение транспилера через опцию babel
в вашем package.json
. Например, вы можете переопределить пресеты следующим образом:
{
"ava": {
"babel": {
"presets": [
"es2015",
"stage-0",
"react"
]
}
},
}
Вы также можете использовать ключевое слово "inherit"
. В таком случае AVA будет ориентироваться на настройки Babel в ваших .babelrc
или package.json
файлах. Таким образом ваши тест файлы будут транспилированы аналогично вашим исходным файлам, в соответствии с вашими настройками и без необходимости создания отдельных настроек для AVA:
{
"babel": {
"presets": [
"es2015",
"stage-0",
"react"
]
},
"ava": {
"babel": "inherit",
},
}
Важно помнить, что AVA всегда добавляет плагины espower
и transform-runtime
.
AVA поддерживает TypeScript. Вам необходимо настроить транспиллинг собственноручно. Когда Вы устанавливаете module
в commonjs
в Вашем файле tsconfig.json
, TypeScript автоматически найдет определение типов для AVA. Вам необходимо выставить target
в es2015
для использования Promises и асинхронных функций.
AVA в данный момент транспиллит только запущенные тесты. AVA не делает транспиллинг импортированных модулей import
вне теста. Есть веские причины для этого подхода, это может быть не тем, что Вы ожидали!
Если Вы используете Babel, то посмотрите в Babel's require hook для транспиллинга импортированных модулей на лету. Запустите AVA с --require babel-register
(смотрите Командная строка) или настройте package.json
.
Если Вы возвращаете Promise в своем тесте, то Вам не нужно явно завершать тест, так как он завершится сразу после успешного выполнения Promise.
test(t => {
return somePromise().then(result => {
t.is(result, 'unicorn');
});
});
AVA имеет встроенную поддержку генераторов.
test(function * (t) {
const value = yield generatorFn();
t.true(value);
});
AVA имеет поддержку ансихронных функций (async/await).
test(async function (t) {
const value = await promiseFn();
t.true(value);
});
// async arrow function
test(async t => {
const value = await promiseFn();
t.true(value);
});
AVA поддерживает observables типы. Если Вы возвращаете объект типа observable в тесте, AVA дождется завершения до окончания теста.
Вам не нужно использовать "коллбек мод" или вызывать t.end()
.
test(t => {
t.plan(3);
return Observable.of(1, 2, 3, 4, 5, 6)
.filter(n => {
// only even numbers
return n % 2 === 0;
})
.map(() => t.pass());
});
AVA поддерживает использование t.end
как финального коллбека, когда используется традиционный Node.js стиль. AVA ожидает, что любое положительное значение, переданное первым параметром в t.end
является ошибкой. Обратите внимание, что t.end
необходим "коллбек мод", который можно включить, используя модификатор .cb
.
test.cb(t => {
// t.end автоматически проверит ошибку в первом аргументе
fs.readFile('data.txt', t.end);
});
AVA может сгенерировать TAP вывод через опцию --tap
для любого из TAP reporter.
$ ava --tap | tap-nyan
AVA автоматически удаляет ненужные строки в Stack trace, что позволить более быстро найти источник ошибки.
Тип: string
Заголовок теста.
Тип: function
Функция теста.
Тип: object
Выполняемый объект конкретного теста. Каждый коллбек теста получает разный объект. Содержит проверки, а так же .plan(count)
и .end()
методы. t.context
может содержать расшаренное состояние из beforeEach
хуков.
План о количестве проверок в тесте. Тест завершится ошибкой, если количество выполненных проверок не будет соответствовать запланированным. Смотрите [план проверок](#План проверок).
Завершить тест. Используется только с test.cb()
.
Проверки встроены в выполняемый объект, который доступен в каждом коллбеке теста:
test(t => {
t.ok('unicorn'); // проверка
});
Если множество проверок завершились ошибкой в одном тесте, AVA отобразит лишь первую ошибку.
Успешная проверка.
Ошибочная проверка.
Проверка, что значение value
истинно.
Проверка, что значение value
ложно.
Проверка, что значение value
- true
.
Проверка, что значение value
- false
.
Проверка, что значение value
эквивалентно expected
.
Проверка, что значение value
не эквивалентно expected
.
Проверка, что значение value
полностью совпадает(deep equal) с expected
.
Проверка, что значение value
не полностью совпадает(not deep equal) с expected
.
Проверка, что function
вызовет ошибку или promise
завершиться с ошибкой.
error
может быть конструктором, регулярным выражением, сообщением об ошибке или функцией валидации.
Возвращает ошибку, которую вернула function
или rejection из promise
.
Проверка, что function
не вызовет ошибку error
или promise
завершится успешно.
Проверка, что contents
подходит под regex
.
Проверка, что error
ложно.
Любую проверку можно пропустить, используя skip
модификатор. Пропущенные проверки подсчитываются, так что Вам не нужно менять запланированное число проверок.
test(t => {
t.plan(2);
t.skip.is(foo(), 5); // не нужно менять количество запланированных проверок
t.is(1, 1);
});
В AVA включена power-assert
библиотека, предоставляющая более информативные сообщения проверок. Она читает Ваш тест и пытается получить дополнительную информацию из Вашего кода.
Посмотрим на пример, использующий стандартный Node.js assert
модуль:
const a = /foo/;
const b = 'bar';
const c = 'baz';
require('assert').ok(a.test(b) || b === c);
Если Вы выполните этот код, будет возвращено:
AssertionError: false == true
В AVA этот тест:
test(t => {
const a = /foo/;
const b = 'bar';
const c = 'baz';
t.ok(a.test(b) || b === c);
});
Вернет следующий результат:
t.ok(a.test(b) || b === c)
| | | |
| "bar" "bar" "baz"
false
Каждый тестовый файл запускается в отдельном процессе Node.js. Это позволяет менять глобальное состояние или делать monkey-patching встроенных методов в одном тестовом файле, без влияния на другие тесты. Это также здорово влияет на производительность в современных мульти-процессорных системах, позволяя выполнять тесты параллельно.
Запуск тестов одновременно имеет свои сложности, выполнение IO одна из них.
Обычно, последовательные тесты создают временный каталог в текущей директории тестов и очищают его после выполнения. Такая схема не будет работать с тестами, запущенными одновременно, так как каждый из тестов бует конфликтовать с другим. Более правильный путь - это создавать новый временный каталог для каждого теста. tempfile
и temp-write
модули могут помочь с этим.
AVA по умолчанию запускает тесты одновременно/параллельно, что не всегда оптимально для отладки. Вместо этого, можно запустить тесты последовательно с аргументом --serial
:
$ ava --serial
Для покрытия кода Вы не можете использовать istanbul
, так как AVA использует изолированное окружение для каждого файла, однако Вы можете использовать nyc
, который похож на istanbul
но с поддержкой запуска в отдельном окружении(sub-process).
Начиная с версии 5.0.0
используются source maps для отчета о покрытии кода, независимо от транспиллинга. Убедитесь, что код, который Вы тестируете содержит инлайны с source map или ссылку на source map файл. Если Вы используете babel-register
Вы можете выставить опцию sourceMaps
в Вашем .babelrc
файле на inline
.
Mocha требует использование неявных глобальных метоов describe
и it
в своем интерфейсе по умолчанию(большинство людей используют это), что слишком догматично, раздуто, синхронно по умолчанию, непригодно для программных API, последовательно и слишком медленно.
Tape и node-tap вполне хороши. AVA была вдохновлена их синтаксисом. Однако они обе выполняют тесты последовательно и они делают TAP своей основной идеей, что сделало их кодовую базу запутанной и связанной. TAP вывод слишком сложен для чтения, так что Вы всегда должны использовать сторонний tap обработчик.
AVA является достаточно качественным и конкурентным продуктом. В AVA включен стандартный и простой обработчик вывода, поддерживающий TAP через параметры командной строки.
AVA поддерживает TAP формат и совместим с любым из TAP reporter'ов.
AVA, не Ava или ava. Произносится как /ˈeɪvə/
ay-və.
Concurrency is not parallelism. It enables parallelism.
- Покрытие кода
- Режим наблюдения
- Тестирование HTTP серверов
- Когда применять
t.plan()
- Тестирование в браузере
- TypeScript
- sublime-ava - Snippets for AVA tests
- atom-ava - Snippets for AVA tests
- vscode-ava - Snippets for AVA tests
- eslint-plugin-ava - Lint rules for AVA tests
- gulp-ava - Run tests with gulp
- grunt-ava - Run tests with grunt
- fly-ava - Run tests with fly
- start-ava - Run tests with start
Sindre Sorhus | Vadim Demedes | James Talmage | Mark Wubben |