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

Написание модульных тестов - одна из тех вещей, которые многие люди забывают делать или вообще избегают, но когда они у вас есть, они спасают вас. Разработка через тестирование [https://en.wikipedia.org/wiki/Test-driven_development], что означает, что вы пишете тесты до кода, является отличной целью, к которой нужно стремиться, но требует дисциплины и планирования при программировании. . Чтобы упростить весь этот процесс, вам понадобятся простые в использовании и мощные фреймворки для тестирования и утверждения, что и есть в Mocha.

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

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

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

Чай

Chai - это библиотека утверждений, которая предоставляет стили программирования BDD и TDD для тестирования вашего кода в любой среде тестирования.

В этой статье мы сосредоточимся на стиле BDD с использованием интерфейса expect

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

 var user = {name: 'Scott'}; 
 
 // Requirement: The object 'user' should have the property 'name' 
 
 expect(user).to.have.property('name'); 

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

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

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

 "use strict"; 
 
 var expect = require('chai').expect; 
 
 // Simple assertions 
 expect({}).to.exist; 
 expect(26).to.equal(26); 
 expect(false).to.be.false; 
 expect('hello').to.be.string; 
 
 // Modifiers ('not') 
 expect([1, 2, 3]).to.not.be.empty; 
 
 // Complex chains 
 expect([1, 2, 3]).to.have.length.of.at.least(3); 

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

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

Возьмем, к примеру, chai-http , плагин, который помогает тестировать маршруты сервера.

 "use strict"; 
 
 var chai = require('chai'); 
 var chaiHttp = require('chai-http'); 
 
 chai.use(chaiHttp); 
 
 chai.request(app) 
 .put('/api/auth') 
 .send({username: ' [email protected] ', passsword: 'abc123'}) 
 .end(function(err, res) { 
 expect(err).to.be.null; 
 expect(res).to.have.status(200); 
 }); 

Мокко

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

Чтобы использовать Mocha, я предлагаю вам установить его глобально с помощью npm:

 $ npm install mocha -g 

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

Создавать тестовые примеры легко с помощью метода describe() describe() используется для структурирования ваших тестов путем группирования других вызовов describe() it() вместе, где и находятся фактические тесты. Вероятно, лучше всего это описать на примере:

 "use strict"; 
 
 var 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); 
 }); 
 }); 
 }); 

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

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

 $ mocha . 
 
 
 Math 
 #abs() 
 ✓ should return positive value of given number 
 
 
 1 passing (9ms) 

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

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

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

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

Лично мне нравится использовать суффикс .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 не будет содержать никаких реальных модульных тестов, только служебные функции, помогающие с тестированием.

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

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

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

 "use strict"; 
 
 var 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"; 
 
 var 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() : запускается перед всеми тестами в данном блоке
  • beforeEach() : запускается перед каждым тестом в данном блоке
  • after() : запускается после всех тестов в данном блоке
  • afterEach() : запускается после каждого теста в данном блоке

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

 "use strict"; 
 
 var expect = require('chai').expect; 
 var Camo = require('camo'); 
 var User = require('../models').User; 
 
 describe('Users', function() { 
 
 var database = null; 
 
 before(function(done) { 
 Camo.connect('mongodb://localhost/app_test').then(function(db) { 
 database = db; 
 return database.dropDatabase(); 
 }).then(function() {}).then(done, done); 
 }); 
 
 afterEach(function(done) { 
 database.dropDatabase().then(function() {}).then(done, done); 
 }); 
 
 describe('#save()', function() { 
 it('should save User data to database', function(done) { 
 // Use your database here... 
 }); 
 }); 
 
 describe('#load()', function() { 
 it('should load User data from database', function(done) { 
 // Use your database here... 
 }); 
 }); 
 }); 

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

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

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

В большинстве случаев это довольно просто. Предполагая, что вы уже установили 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 <pattern> или -f <sub-string> .

Опять же, используя приведенные выше примеры, мы можем использовать параметр -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() не были включены в этот прогон. Если вы планируете соответственно с именами ваших тестов, эту опцию можно использовать только для запуска определенных разделов ваших тестов.

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

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

Вы можете проверить полный список параметров с помощью команды mocha -h или на этой странице .

Где узнать больше

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

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

Изучите модульное тестирование Javascript с помощью Mocha, Chai и Sinon{.udemy-link}

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

Заключение

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

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

Есть какие-нибудь полезные советы по написанию тестов Mocha / Chai? Дайте нам знать об этом в комментариях!

comments powered by Disqus