Как стать автором
Обновить

AVA — Футуристическая JavaScript библиотека для тестирования

Время на прочтение5 мин
Количество просмотров14K

В этой статье я хочу представить вам новую библиотеку для тестирования 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 заодно замерю скорость выполнения и сложность перехода.

Полезные ссылки:


Теги:
Хабы:
+15
Комментарии20

Публикации

Изменить настройки темы

Истории

Работа

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн