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

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


Поделиться с друзьями
-->

Комментарии (20)


  1. mwizard
    24.10.2016 18:58
    +3

    И в чем разница с Mocha, кроме названия?


    1. Vovchikvoin
      24.10.2016 21:27
      -1

      Я лично не юзал AVA, но как понял из статьи, отличие от мочи — свой assertion, никаких chai; из коробки ES6;


      1. alekseyleshko
        24.10.2016 22:03

        AVA это основа. Минимум всего(но хватает для работы), ES6, параллельный запуск тестов и изоляцией.
        Про assertion, на текущий момент я так понял, что только базовые. И это будет либо расширятся, либо уже сейчас можно сделать свою версию ava-assert.


        Mocha с 2011 года, AVA всего 2. Надо подождать развития и посмотреть, что будет предложено сообществом.
        Но на мой взгляд достойный конкурент.


    1. alekseyleshko
      24.10.2016 21:39

      На мой взгляд, сейчас тенденция делать параллельно все в окружении в JS: gulp пришел на место grunt, yarn заявляет права на пакетный менеджер npm.
      Поэтому это вроде как логичное развитие событий. Основное что дает AVA это скорость выполнение тестов. Это довольно важно. А на каких то проектах может быть и критично.
      На мой взгляд пример Pageres от 31 секунд до 11 это хорошо. Но показательные будет уже большой коммерческий проект, так что ждем.


      Кастомизация assertion возможна в AVA. Но базовый API assertion довольно маленький, но покрывает основные потребности.


      И да ES6 из коробки, просто факт что уже пора использовать.


      1. webschik
        24.10.2016 23:12

        Если говорить о скорости и параллельном выполнении, мне очень нравится Jest. Сравнивали с AVA?


        1. alekseyleshko
          24.10.2016 23:59

          Jest, честно сказать впервые слышу, но обязательно посмотрю подробнее.
          Бегло пробежался, это facebook разработчики(отсылка к yarn). Jest с AVA очень похожи на между собой.
          API и assertion, что то близкое к jasmine. Mock-и из коробки, очень интересно.


          У Jest по понятным причинам сразу тестирование React-а в примерах, у AVA тоже. Оба используют enzyme.
          Была идея сравнить по скорости AVA с Mocha и Jasmine, но там вроде как заведомо не равный бой.
          А тут прям брат близнец, причем оба проекта начались в 2014 году с разницей в полгода.
          Может быть стоит все таки сделать какой то сравнение/срез. Может быть будет интересно. Хотя даже если они будет почти идентичны, все равно будет интересно.


          1. webschik
            25.10.2016 09:43

            Jest внутри использует Jasmine, но API позволяет использовать другой движок. Я узнал о Jest, когда начал разработку на React Native, но сейчас использую и в других проектах, без привязки к React.


            На одном рабочем проекте мигрировали на Jest с Karma + Jasmine, именно из-за производительности.
            Сейчас такая картина для unit-тестов:


            Using Jest CLI v14.1.0, jasmine2
            ...
            21891 tests passed (21891 total in 2123 test suites, run time 35.685s)

            Кстати, у них есть раздел для пользователей AVA и Tape :)


            1. alekseyleshko
              25.10.2016 10:08

              Понял, я почитал тоже немного о нем чуть-чуть больше узнал о нем.


              На мой взгляд у Вас достойный результат по тестированию. А мигрировали с чего? И там какой показатель был?


              Легкость переходана новую либу тестирование это важно, особено при миграции.
              У Jest более живое сообщество, как я посмотрю. Но он и на полгода старше. AVA имеет хорошие показатели интереса.


              1. webschik
                25.10.2016 10:14

                Раньше в проекте unit-тесты запускались на Karma.js и написаны были на Jasmine. Эдакая устоявшаяся классика :)


                К сожалению не помню результатов на старой связке, перешли примерно полгода назад, результаты были ужасными, как по мне, что-то около 2х минут.


                1. alekseyleshko
                  25.10.2016 10:39

                  Люблю эту(jasmine + karma) связку, тоже часто использовал.


                  Понял, результат отличный.


      1. Odrin
        25.10.2016 10:06

        В чем заключается это «ES6 из коробки»? Какое отношение библиотека имеет к es? Они же не тащат вместе с собой отдельный интерпретатор.


        1. alekseyleshko
          25.10.2016 12:44

          Либа с зависимостях ташит как раз Babeljs, что как раз позволяет писать тесты на ES6. Чтобы писать код в es6 и его тестировать, сам код модулей надо обрабатывать. В статье простой способ это сделать.


  1. 776166
    24.10.2016 19:59
    +2

    От какого слова происходит в названии «футурестическая»?


    1. antonksa
      24.10.2016 20:03
      -1

      Лучше не спрашивайте — кошмары сниться будут )))


    1. alekseyleshko
      24.10.2016 21:26
      +1

      Спасибо, исправил! Я честно старался. Вычитывал. Но совсем забыл про название.


  1. bambruysk
    24.10.2016 21:26

    «Футурестическая» — это опечатка или хитрый каламбур?


    1. alekseyleshko
      24.10.2016 21:27

      Ох если бы. Спасибо, исправил.



  1. justboris
    25.10.2016 12:19
    +5

    User experience у инструмента не очень. На первый взгляд все красиво, ES6, async и тому подобные прелести.


    А потом выясняется, что есть баг в такой базовой вещи, как test.only и доверие к иструменту падает.


    Та же ситуация и в коммьюнити. Люди, два года назад хвалившие AVA, сейчас мигрируют на Jest и нахваливают его не меньше.


    И, наконец, сам автор AVA говорит, что библиотека не расчитана на тестирование UI-компонентов и была изначальна предназначена для тестирования node.js-модулей, которых у него великое множество.


    Следует учитывать эти моменты при выборе библиотеки для тестирования своего проекта