Тестирование кода Node.js с помощью Mocha и Chai

Введение

Написание модульных тестов — это то, что как начинающие, так и опытные инженеры обычно откладывают на более поздние этапы разработки, тем не менее — они являются ключом к стабильной и надежной разработке программного обеспечения.

Основная предпосылка разработка через тестирование (TDD) пишет ваши тесты еще до того, как вы начнете программировать. Это отличная цель, к которой нужно стремиться, но она требует большой дисциплины и планирования, когда вы пытаетесь следовать ее принципам! Чтобы сделать весь этот процесс намного проще, вы можете прибегнуть к простым в использовании и мощным платформам тестирования и утверждений, таким как Кофе мокко и Чай.

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

Чай

Chai — это библиотека утверждений, которая предоставляет как BDD (разработка, основанная на поведении) и TDD (разработка через тестирование) стили программирования для тестирования кода и предназначены для работы в паре с библиотекой тестирования, позволяющей организовывать тесты. Его очень часто сочетают с мокко.

Он имеет три основных API:

  • should
  • expect
  • assert

var.should.equal(var2)


expect.var.to.be.equal(var2)


assert.equal(var1, var2)

В этой статье мы сосредоточимся на стиле BDD, используя метод Chai. expect интерфейс, хотя использование других интерфейсов/стилей в соответствии с вашей собственной интуицией совершенно нормально. assert Интерфейс является наиболее похожим на распространенные платформы утверждений TDD.

expect использует очень естественный языковой API для написания ваших утверждений, что облегчит написание ваших тестов и улучшит их позже в будущем. Это делается путем объединения геттеров для создания и выполнения утверждения, что упрощает преобразование требований в код:

let user = {name: 'Scott'};


expect(user).to.have.property('name');

Примечание: Посмотрите, как вы можете прочитать утверждение на естественном языке и понять, что происходит? Это одно из основных преимуществ использования такой библиотеки утверждений, как Chai!

Еще несколько примеров таких геттеров:

  • to
  • be
  • is
  • and
  • has
  • have

Многие из этих геттеров могут быть объединены в цепочку и использоваться с такими методами утверждения, как true, ok, existи empty чтобы создать несколько сложных утверждений всего в одной строке:

"use strict";

const expect = require('chai').expect;


expect({}).to.exist;
expect(26).to.equal(26);
expect(false).to.be.false;
expect('hello').to.be.string;


expect([1, 2, 3]).to.not.be.empty;


expect([1, 2, 3]).to.have.length.of.at.least(3);

Примечание: Полный список доступных методов можно найти здесь.

Вы также можете проверить список доступных плагины для Чай. Это значительно упрощает тестирование более сложных функций.

взять чай-http например, это плагин, который помогает вам тестировать маршруты сервера:

"use strict";

const chai = require('chai');
const chaiHttp = require('chai-http');

chai.use(chaiHttp);

chai.request(app)
    .put('/api/auth')
    .send({username: '[email protected]', password: 'abc123'})
    .end(function(err, res) {
        expect(err).to.be.null;
        expect(res).to.have.status(200);
    });

Организация тестовых случаев с помощью Mocha — description() и it()

Mocha — это среда тестирования для Node, которая дает вам возможность запускать асинхронный (или синхронный) код последовательно. Любые неперехваченные исключения отображаются вместе с тестовым набором, в котором они были созданы, что позволяет легко определить, что именно не удалось и почему.

Рекомендуется установить Mocha глобально:

$ npm install mocha -g

Вы хотите, чтобы это была глобальная установка, так как mocha Команда используется для запуска тестов проекта в вашем локальном каталоге.

Что делает этот фрагмент кода?

it() должен вернуть Х. it() определяет тестовые случаи, и Mocha будет запускать каждый it() как модульный тест. Чтобы организовать несколько модульных тестов, мы можем describe() общая функциональность и, таким образом, структура тестов Mocha.

Это, вероятно, лучше всего описать на конкретном примере:

"use strict";
const expect = require('chai').expect;

describe('Math', function() {
    describe('#abs()', function() {
        it('should return positive value of given negative number', function() {
            expect(Math.abs(-5)).to.be.equal(5);
        });
    });
});

В describe() метод, мы определили название теста, называемые #abs(). Вы также можете запускать тесты по отдельности по их имени — это будет рассмотрено позже.

Примечание: С тестами Mocha вам не нужно require() любой из методов Мокко. Эти методы предоставляются глобально при запуске с mocha команда.

Чтобы запустить эти тесты, сохраните файл и используйте mocha команда:

$ mocha .

  Math
    #abs()
      ✓ should return positive value of given number 


  1 passing (9ms)

Результатом является разбивка выполненных тестов и их результатов. Обратите внимание, как вложенный describe() вызовы переносятся на вывод результатов. Полезно иметь все тесты для данного метода или функции вложенными вместе.

Эти методы лежат в основе среды тестирования Mocha. Используйте их, чтобы составлять и организовывать свои тесты так, как вам нравится. Мы увидим один пример этого в следующем разделе.

Написание тестов с Mocha и Chai

Рекомендуемый способ организовать ваши тесты в вашем проекте — поместить их все в свои собственные тесты. /test каталог. По умолчанию Mocha проверяет модульные тесты, используя globs ./test/*.js и ./test/*.coffee. Оттуда он загрузит и выполнит любой файл, который вызывает describe() метод.

Ознакомьтесь с нашим практическим руководством по изучению Git с рекомендациями, принятыми в отрасли стандартами и прилагаемой памяткой. Перестаньте гуглить команды Git и на самом деле изучить это!

Обычно к тестовым файлам добавляется суффикс .test.js для исходных файлов, содержащих тесты Mocha:

├── package.json
├── lib
│   ├── db.js
│   ├── models.js
│   └── util.js
└── test
    ├── db.test.js
    ├── models.test.js
    ├── util.test.js
    └── util.js

util.js в test каталог не будет содержать никаких модульных тестов, только служебные функции, помогающие в тестировании.

Внимание: Вы можете использовать любую структуру, которая имеет для вас смысл, модульные тесты подбираются автоматически.

Когда дело доходит до фактического написания тестов, это помогает организовать их с помощью describe() методы. Вы можете организовать их по функциям, функциям, файлам или любому другому произвольному уровню. Например, тестовый файл, организованный для описания работы на функциональном уровне, выглядит так:

"use strict";

const expect = require('chai').expect;

describe('Math', function() {
    describe('#abs()', function() {
        it('should return positive value of given negative number', function() {
            expect(Math.abs(-5)).to.be.equal(5);
        });

        it('should return positive value of given positive number', function() {
            expect(Math.abs(3)).to.be.equal(3);
        });

        it('should return 0 given 0', function() {
            expect(Math.abs(0)).to.be.equal(0);
        });
    });
});

Запуск тестов даст вам результат:

$ mocha .

  Math
    #abs()
      ✓ should return positive value of given negative number 
      ✓ should return positive value of given positive number 
      ✓ should return 0 given 0 


  3 passing (11ms)

Расширяясь еще больше, вы можете даже иметь тесты для нескольких методов в одном файле. В этом случае методы группируются по Math объект:

"use strict";

const expect = require('chai').expect;

describe('Math', function() {
    describe('#abs()', function() {
        it('should return positive value of given negative number', function() {
            expect(Math.abs(-5)).to.be.equal(5);
        });

        it('should return positive value of given positive number', function() {
            expect(Math.abs(3)).to.be.equal(3);
        });

        it('should return 0 given 0', function() {
            expect(Math.abs(0)).to.be.equal(0);
        });
    });

    describe('#sqrt()', function() {
        it('should return the square root of a given positive number', function() {
            expect(Math.sqrt(25)).to.be.equal(5);
        });

        it('should return NaN for a given negative number', function() {
            expect(Math.sqrt(-9)).to.be.NaN;
        });

        it('should return 0 given 0', function() {
            expect(Math.sqrt(0)).to.be.equal(0);
        });
    });
});

Что приводит к:

$ mocha .

  Math
    #abs()
      ✓ should return positive value of given negative number 
      ✓ should return positive value of given positive number 
      ✓ should return 0 given 0 
    #sqrt()
      ✓ should return the square root of a given positive number 
      ✓ should return NaN for a given negative number 
      ✓ should return 0 given 0 


  6 passing (10ms)

Крючки Mocha — before(), after(), beforeEach() и afterEach()

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

  • before(): Запускается перед всеми тестами в данном блоке
  • beforeEach(): Запускается перед каждым тестом в данном блоке
  • after(): Запускается после всех тестов в данном блоке.
  • afterEach(): Запускается после каждого теста в данном блоке

Эти хуки — идеальное место для выполнения работ по настройке и демонтажу, необходимых для ваших тестов. Один из распространенных вариантов использования — установить соединение с вашей базой данных перед запуском тестов:

"use strict";

const expect = require('chai').expect;
let User = require('../models').User;

describe('Users', function() {

    let database = null;

    before(function(done) {
        
    });

    afterEach(function(done) {
        
    });

    describe('#save()', function() {
        it('should save User data to database', function(done) {
            
        });
    });

    describe('#load()', function() {
        it('should load User data from database', function(done) {
            
        });
    });
});

Перед тем, как любой тестов запущено, функция отправлена ​​в наш before() запускается метод (и запускается только один раз в тестах), который устанавливает соединение с базой данных. Как только это будет сделано, наши наборы тестов будут запущены.

Поскольку мы не хотим, чтобы данные из одного набора тестов влияли на другие наши тесты, нам необходимо очищать данные из нашей базы данных после запуска каждого набора. Это то, что afterEach() это для. Мы используем этот хук, чтобы очистить все данные базы данных после каждый тестовый пример запущен, поэтому мы можем начать с чистого листа для следующих тестов.

Запуск тестов Mocha

В большинстве случаев эта часть довольно проста. Предполагая, что вы уже установили Mocha и перешли в каталог проекта, большинству проектов просто нужно использовать mocha команда без аргументов для запуска своих тестов:

$ mocha


  Math
    #abs()
      ✓ should return positive value of given negative number 
      ✓ should return positive value of given positive number 
      ✓ should return 0 given 0 
    #sqrt()
      ✓ should return the square root of a given positive number 
      ✓ should return NaN for a given negative number 
      ✓ should return 0 given 0 


  6 passing (10ms)

Это немного отличается от наших предыдущих примеров, поскольку нам не нужно было сообщать Mocha, где расположены наши тесты. В этом примере тестовый код находится в ожидаемом месте /test.

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

Для подобных случаев следует сказать Mocha, какие тесты запустить. Это можно сделать с помощью -g or -f настройки.

Для запуска отдельных тестов вы можете предоставить -g флаг и добавьте общий шаблон между тестами, которые вы хотите запустить. Например, если вы хотите запустить #sqrt() Тесты:

$ mocha -g sqrt

  Math
    #sqrt()
      ✓ should return the square root of a given positive number 
      ✓ should return NaN for a given negative number 
      ✓ should return 0 given 0 


  3 passing (10ms)

Обратите внимание, что #abs() тесты не были включены в этот запуск. Если вы соответствующим образом планируете имена тестов, этот параметр можно использовать для запуска только определенных разделов ваших тестов.

Однако это не единственные полезные опции. Вот еще несколько вариантов мокко, которые вы, возможно, захотите проверить:

  • --invert: инвертирует -g и -f спички
  • --recursive: Включить подкаталоги
  • --harmony: включить все функции гармонии в Node.

Внимание: Вы можете просмотреть полный список параметров, используя mocha -h команду или на эту страницу.

Где узнать больше? Эта тема гораздо шире, чем мы можем осветить в короткой статье, поэтому, если вы хотите узнать больше, мы рекомендуем проверить официальный Кофе мокко и Чай документация.

Заключение

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

Надеюсь, это послужило полезным знакомством с мокко и чаем. Существует гораздо больше информации, чем то, что я представил здесь, поэтому обязательно ознакомьтесь с документацией для получения дополнительной информации.

Отметка времени:

Больше от Стекабьюс