Рубрики
Без рубрики

Устройство тестирования и TDD в Node.js – Часть 1

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

Автор оригинала: David Tang.

Тестирование является важной практикой в разработке программного обеспечения для улучшения качества программного обеспечения. Есть много форм тестирования; Ручное тестирование, тестирование приема, тестирование подразделения и несколько других. В этом посте мы будем смотреть на тестирование подразделения в узле, используя Моча Тестовые рамки. Агрегаты, как правило, составляют большинство тестовых люксов. Они тестируют небольшие единицы кода, как правило, метод или функция, в изоляции Отказ Ключевая вещь, которую нужно помнить, это в изоляции аспект.

В этом посте мы начнем с написания модульных тестов для функции, которая просто требует некоторого ввода, возвращает некоторые вывод и не имеет зависимостей. Тогда мы рассмотрим два типа теста удваивания, заглушки и шпионы, используя библиотеку SINON. Наконец, мы посмотрим, как тестировать асинхронный код в Mocha. Давайте начнем!

Установка Mocha и Chai

Чтобы установить Mocha, просто запустите:

npm install mocha -g

В отличие от других структур тестирования JavaScript, таких как Жасмин и Кенет, Мока не поставляется с библиотекой утверждения. Вместо этого Mocha позволяет вам выбрать свой собственный. Популярные вкладные библиотеки, используемые с Mocha, включают должен .js , veged.js , Чай и узел встроен в Assert модуль. В этом посте мы собираемся использовать Чай.

Во-первых, давайте создадим Package.json Файл и установить Чай:

touch package.json
echo {} > package.json
npm install chai --save-dev

Чай поставляется с тремя разными ароматами утверждений. У этого есть Должен Стиль, ожидать стиль и Assert стиль. Все они получают работу, и выбор – это просто вопрос предпочтений в том, как вы хотите, чтобы язык ваших тестов читать. Лично мне нравится ожидать стиль, поэтому мы будем использовать это.

Ваш первый тест

( Исходный код для проекта )

Для нашего первого примера мы будем использовать тестовое развитие (TDD), чтобы создать Cartsumbary Функция конструктора, которая будет использоваться для общего количества предметов, помещенных в корзину. Короче говоря, TDD – это практика написания тестов перед реализацией для управления дизайном вашего кода. TDD практикуется в следующих шагах:

  1. Написать тест и просмотреть его
  2. Напишите минимальное количество кода, чтобы сделать этот тестовый пропуск
  3. Повторить

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

// tests/part1/cart-summary-test.js
var chai = require('chai');
var expect = chai.expect; // we are using the "expect" style of Chai
var CartSummary = require('./../../src/part1/cart-summary');

describe('CartSummary', function() {
  it('getSubtotal() should return 0 if no items are passed in', function() {
    var cartSummary = new CartSummary([]);
    expect(cartSummary.getSubtotal()).to.equal(0);
  });
});

Опишите Функция используется для настройки группы тестов с именем. Я склонен ставить модуль в тесте как имя, в этом случае Cartsumbary Отказ Тест написан с использованием Это функция. Это Функция дана описание в качестве первого аргумента того, что должен делать тест модуля. Второй аргумент Это Функция – это функция, которая будет содержать одно или несколько утверждений (также называемых ожиданиями), используя Chai в этом примере. Наш первый тест просто проверяет, что субтетал 0, если у тележки нет предметов.

Чтобы запустить этот тест, запустить Mocha Tests --recursive --Watch от корня проекта. Рекурсивный флаг найдет все файлы в подкаталогах, и флаг Watch будет смотреть все ваши исходные и тестовые файлы и повторить тесты, когда они меняются. Вы должны увидеть что-то вроде этого:

Неспособность-тест-1.png

Наш тест не проходит, потому что мы еще не реализованы Cartsumbary Отказ Давайте сделаем это.

// src/part1/cart-summary.js
function CartSummary() {}

CartSummary.prototype.getSubtotal = function() {
  return 0;
};

module.exports = CartSummary;

Здесь мы написали минимальное количество кода, чтобы сделать наш тест.

Прохождение теста-1

Давайте перейдем к нашему следующему тесту.

it('getSubtotal() should return the sum of the price * quantity for all items', function() {
  var cartSummary = new CartSummary([{
    id: 1,
    quantity: 4,
    price: 50
  }, {
    id: 2,
    quantity: 2,
    price: 30
  }, {
    id: 3,
    quantity: 1,
    price: 40
  }]);

  expect(cartSummary.getSubtotal()).to.equal(300);
});
неудача-тест-2.png

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

// src/part1/cart-summary.js
function CartSummary(items) {
  this._items = items;
}

CartSummary.prototype.getSubtotal = function() {
  if (this._items.length) {
    return this._items.reduce(function(subtotal, item) {
      return subtotal += (item.quantity * item.price);
    }, 0);
  }

  return 0;
};

Наш тест проходит! Мы успешно использовали TDD для реализации getsubtotal метод.

Заглушки с синоном

Допустим, мы сейчас хотим добавить налоговый расчет на Cartsumbary в оформлении GetTax () метод. Конечное использование будет выглядеть так:

var cartSummary = new CartSummary([ /* ... */ ]);
cartSummary.getTax('NY', function() {
  // executed when the tax API request has finished
});

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

Как упоминалось ранее, единичные тесты тестовые единицы в изоляции. Мы хотим проверить наши GetTax Способ изолирован от налог. Калкуляция Отказ До тех пор, пока налог. Калкуляция пребывает по его коду договору или интерфейсу, GetTax должно сработать. Что мы можем сделать, это подделывает налог. Калкуляция При тестировании GetTax Использование заглушки, тип тестирования двойной, который действует как управляемая замена. Проверенные удваивания часто сравниваются с трюком удваиваний, поскольку они заменяют один объект с другим для целей тестирования, аналогично тому, как актеры и актрисы заменяются востребом удваиваний для опасных сцен действий. Мы можем создать эту заглушку с помощью библиотеки SINON.

Чтобы установить Sinon, запустите:

npm install sinon --save-dev

Первое, что мы должны сделать, прежде чем мы сможем заглушить налог. Калкуляция Метод определяет его. Нам не нужно реализовывать детали этого, но метод рассчитать должен существовать на налог объект.

// src/part1/tax.js
module.exports = {
  calculate: function(subtotal, state, done) {
    // implemented later or in parallel by our coworker
  }
};

Теперь, когда налог. Калкуляция Было создано, мы можем опустить его с нашей предварительно запрограммированной заменой, используя SINON:

// tests/part1/cart-summary-test.js
// ...
var sinon = require('sinon');
var tax = require('./../../src/part1/tax');

describe('getTax()', function() {
  beforeEach(function() {
    sinon.stub(tax, 'calculate', function(subtotal, state, done) {
      setTimeout(function() {
        done({
          amount: 30
        });
      }, 0);
    });
  });

  afterEach(function() {
    tax.calculate.restore();
  });

  it('get Tax() should execute the callback function with the tax amount', function(done) {
    var cartSummary = new CartSummary([{
      id: 1,
      quantity: 4,
      price: 50
    }, {
      id: 2,
      quantity: 2,
      price: 30
    }, {
      id: 3,
      quantity: 1,
      price: 40
    }]);

    cartSummary.getTax('NY', function(taxAmount) {
      expect(taxAmount).to.equal(30);
      done();
    });
  });
});

Начнем с требования Sinon и нашего налогового модуля в тесте. Распустить метод в Синоне, мы называем Sinon.stub Функция и пропуская ее объект с помощью метода, окрашиваемого, название метода, которое необходимо ограбить и функцию, которая заменит оригинал во время нашего теста.

var stub = sinon.stub(object, 'method', func);

В этом примере я просто устал …| налог. Калкуляция со следующим:

function(subtotal, state, done) {
  setTimeout(function() {
    done({
      amount: 30
    });
  }, 0);
}

Это просто функция, которая звонит сделано С объектом статической налоговой информации, содержащий налоговую сумму 30. Сетримс Используется для подражания асинхронного поведения этого метода, так как на самом деле он будет делать асинхронный вызов API к некоторой налоговой службе. Это происходит в Rebedeach блок, который выполняет перед каждым тестом. После каждого теста ДОПОЛЮЧЕНИЕ Блок выполнен, который восстанавливает оригинал налог. Калкуляция Отказ

Этот тест проверяет, что функция обратного вызова передана GetTax Выполняется с суммой налога, а не все объект налоговой информации, который передается в функцию обратного вызова для налог. Калкуляция Отказ Как видите, наш тест на GetTax проходит, даже если мы не реализовали налог. Калкуляция еще. Мы просто определили интерфейс этого. До тех пор, пока налог. Калкуляция Обесполняет этот интерфейс, оба модуля должны работать правильно вместе.

Этот пример также демонстрирует асинхронное тестирование. Указание параметра в Это Функция (называемая сделано в этом примере), Mocha будет проходить функцию и ждать его выполнения перед завершением теста. Тест будет время ожидания и ошибка, если сделано не вызывается в течение 2000 миллисекунд. Если бы мы не сделали это асинхронный тест, тест закончил бы до того, как наше ожидание будет проходить, привело к тому, что мы думаем, что все наши тесты проходят, когда на самом деле они нет.

Теперь давайте напишем реализацию для GetTax сделать наш тест-пропуск:

CartSummary.prototype.getTax = function(state, done) {
  tax.calculate(this.getSubtotal(), state, function(taxInfo) {
    done(taxInfo.amount);
  });
};

Шпионы с синоном

Один вопрос, что наше GetTax Метод имеет то, что наш тест не проверяет, что налог. Калкуляция называется с правильным субтотальным и состоянием. Наш тест все равно пройдет, если мы жесткокодируем субтотальные и состоятельные значения в GetTax выполнение. Продолжай и попробую в Образец кода Отказ Это не хорошо! Проверить налог. Калкуляция Вызывается с правильными аргументами, мы можем использовать Sinon Spies.

SPY – это другой тип теста, который записывает, как используется функция. Это включает в себя информацию, такую как аргументы, с помощью Spy называется, сколько раз называется шпион, и если SPY бросает ошибку. Великая вещь о синонских заглушках состоит в том, что они построены на вершине шпионов! Вот наш обновленный тест:

it('getTax() should execute the callback function with the tax amount', function(done) {
  var cartSummary = new CartSummary([
    {
      id: 1,
      quantity: 4,
      price: 50
    },
    {
      id: 2,
      quantity: 2,
      price: 30
    },
    {
      id: 3,
      quantity: 1,
      price: 40
    }
  ]);

  cartSummary.getTax('NY', function(taxAmount) {
    expect(taxAmount).to.equal(30);
    expect(tax.calculate.getCall(0).args[0]).to.equal(300);
    expect(tax.calculate.getCall(0).args[1]).to.equal('NY');
    done();
  });
});

Еще два ожидания были добавлены к этому тесту. getcall используется, чтобы получить первый звонок на заглушку для налог. Калкуляция Отказ args содержит аргументы для этого звонка. Мы просто проверяем, что налог. Калкуляция был вызван с правильным субтетальным и состоянием в отличие от жесткодируемых ценностей.

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

Заключение

В этом посте мы смотрели на несколько практических примеров тестирования единиц в узле с использованием структуры тестирования MOCHA, библиотеку утверждения Chai и Sinon для теста удваивается в виде окуривания и шпионажа. Я надеюсь, что вам понравилось этот пост. Если у вас есть какие-либо вопросы, спросите их ниже или добраться до меня в Twitter @ SkaterDav85 Отказ

Часть 2 будет о тестировании HTTP-запросов с Nock.

Исходный код