Chai с плюшками

Chaijs

Chai is a BDD / TDD assertion library for node and the browser that can be delightfully paired with any javascript testing framework.

Сам по себе Chai дает большое количество разных функций для проверки тех или иных утверждений в тестах. Так же удобный (читаемый) синтаксис позволяет понять механизм написания проверок почти сходу:

expect(val).to.equal(another_val);
expect(val).to.be.a('string');
....

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

// bad example
expect(val === another_val).to.be.true; // to.be.ok - same

Пока это выражение истинно и тест не «красный», разницы нет никакой. Но, если тест упадет, то Chai выведет сообщение вида: «Expected true to equal false». Сообщение уровня КО. Для отладки придется где-то делать вывод значений val и another_val. А что выведетется при провале утверждения:

var val = '1234',
  another_val = '12345';
expect(val).to.equal(another_val);

Будет выведено сообщение: «Assertiona failed: expected 1234 to equal 12345». Тут уже реально видно, что пошло не так. Время на «ручное» отслеживание значений, которые попали в тест, уже не тратится. Небольшой вывод: нужно использовать как можно больше из того, что дает библиотека, и жизнь станет чуток проще. По ссылке есть много примеров на каждый из доступных методов сравнений в chai.

А что делать, если стандартных средств не хватает? Может в тестах очень много проверок дат или каких-то специфических ситуаций со строками. Примеры:

var date1 = new Date(2013, 4, 30, 16, 5),
  date2 = new Date(2013, 4, 30, 17);
expect(date1).to.equal(date2);

Если тест «зеленый», то проблемы нет (вывело OK и все счастливы). А вот если тест красный, то выведется сообщение вида: «Assertion failed: expected 1369944360000 to equal 1369944300000». То есть, вроде как и понятно, что две временных метки не равны, но вот где именно они не равны — вопрос. Или еще несколько примеров:

var str = 'abcdef',
  substr = 'ab';
expect(str.indexOf(substr) === 0).to.be.true;

Что делает этот тест? Он проверяет, что строка str начинается со строки substr. В случае провала теста будет сообщение: «Assertion failed: expected false to equal true». Не очень информативно. А что если немного переписать:

var str = 'abcdef',
  substr = 'ab';
expect(str.indexOf(substr)).to.equal(0);

В случае провала теста в сообщении будет указана позиция, на которой была найдена substr. Уже лучше. Но все равно, сам по себе тест не очень читается как словосочетание. Куда красивее было бы:

expect(str).to.startsWith(substr);

А если тест будет такой:

var str = 'abcdef',
  substr = 'def';
expect(str.indexOf(substr, str.length - substr.length)).to.not.equal(-1);

В случае провала теста выведется, что -1 таки «equal» -1. Информации ноль. Понять, что реально делает тест, тоже не просто. А если было бы так:

var str = 'abcdef',
  substr = 'def';
expect(str).to.endsWith(substr);

Совсем другое дело. Коротко и ясно.

У Chai есть отличный механизм для написания расширений с новыми типами сравнений. Да и немало плагинов уже написано. Рассмотрим некоторые из них:

chai-datetime

Репозиторий на GitHub.

npm i chai-datetime

На примере выше я показывал, что бывает, если сравнить две даты через equal и что выведется, если они не равны. Данный плагин позволяет избежать таких ситуаций и дает отличный механизм для сравнения дат и времен.

var d1 = new Date(2013, 4, 30, 16, 5),
    d2 = new Date(2013, 4, 30, 17);
expect(d1).to.equalDate(d2);

Вполне читабельный код. Плагин позволяет сравнить даты и времена на равенство и очередность следования (before, after):

  • equalTime
  • beforeTime
  • afterTime
  • equalDate
  • beforeDate
  • afterDate

chai-string

Репозиторий на GitHub.

npm i chai-string

Примеры про startsWith и endsWith были даны выше не просто так. Данное расширение и обеспечивает эти методы, а так же несколько других — equalIgnoreCase, singleLine, reverseOf, palindrome, entriesCount. Несколько примеров:

expect('abcdef').to.equalIgnoreCase('AbCdEf');
expect('abcdef').to.be.singleLine();
expect('abcdef').to.be.reverseOf('fedcba');
expect('abccba').to.be.palindrome();
expect('abcabd').to.have.entriesCount('ab', 2);

chai-json-schema

Репозиторий на GitHub.

npm i chai-json-schema

Работа с объектами сложнее, чем со строками или датой. Особенно, если необходима сложная проверка на наличие/отсутствие некоторых свойств. В Chai «из коробки» есть eql, deep, ownProperty и property. Однако для объекта с несколько свойствами придется писать большое количество expect’ов. Да и в ситуации, когда нужно не точное соответствие значений, а простое наличие тех или иных свойств, eql не поможет. Это не очень удобно. Куда лучше использовать chai-json-schema. Пример из Readme:

var goodApple = {
    skin: "thin",
    colors: ["red", "green", "yellow"],
    taste: 10
};
var badApple = {
    colors: ["brown"],
    taste: 0,
    worms: 2
};
var fruitSchema = {
    "title": "fresh fruit schema v1",
    "type": "object",
    "required": ["skin", "colors", "taste"],
    "properties": {
        "colors": {
            "type": "array",
            "minItems": 1,
            "uniqueItems": true,
            "items": {
                "type": "string"
            }
        },
        "skin": {
            "type": "string"
        },
        "taste": {
            "type": "number",
            "minimum": 5
        }
    }
};
 
expect(goodApple).to.be.jsonSchema(fruitSchema);
expect(badApple).to.not.be.jsonSchema(fruitSchema);

Кажется, что кода много, но это обманчиво. В «реальном» коде будет метод, который возвращает некоторый JSON и схема, по которой он проверятся. Ну и конечно один(!) expect. Или should 🙂 Плюс в том, что такие схемы можно хранить где-то отдельно и подгружать по необходимости. Код будет чистым и понятным. Да и в случае «красного» теста пользователю выведется понятное сообщение о том, что и где пошло не так.

На странице plugins есть большой список дополнений для Chai. Время от времени страничка обновляется с новыми плагинами. Так же разработчики Chai всегда рады новым расширениям. К тому же, писать их совсем не сложно.

, , , ,

Оставить комментарий

Top ↑ | Main page | Back