Выполнение одного и того же теста мокки несколько раз с разными данными
Проблема
У меня есть несколько тестов, которые делают то же самое в мокко. Это для меня, это дублирование, и это худшее, что нужно сделать, когда вы хотите, чтобы ваша система была поддающейся поддержке.
var exerciseIsPetitionActive = function (expected, dateNow) {
var actual = sut.isPetitionActive(dateNow);
chai.assert.equal(expected, actual);
};
test('test_isPetitionActive_calledWithDateUnderNumSeconds_returnTrue', function () {
exerciseIsPetitionActive(true, new Date('2013-05-21 13:11:34'));
});
test('test_isPetitionActive_calledWithDateGreaterThanNumSeconds_returnFalse', function () {
exerciseIsPetitionActive(false, new Date('2013-05-21 13:12:35'));
});
Что мне нужно
Мне нужен способ свернуть мои дублированные тесты мокко только в одном.
Например, в PhpUnit (и других тестовых средах) вы dataProviders.
В phpUnit dataProvider работает следующим образом:
<?php class DataTest extends PHPUnit_Framework_TestCase {
/**
* @dataProvider provider
*/
public function testAdd($a, $b, $c)
{
$this->assertEquals($c, $a + $b);
}
public function provider()
{
return array(
array(0, 0, 0),
array(0, 1, 1),
array(1, 0, 1),
array(1, 1, 3)
);
}
}
Поставщик здесь вводит параметры в тест, а тест выполняет все случаи. Идеально подходит для повторного тестирования.
Я хочу знать, есть ли в мокке что-то подобное, например, что-то вроде этого:
var exerciseIsPetitionActive = function (expected, dateNow) {
var actual = sut.isPetitionActive(dateNow);
chai.assert.equal(expected, actual);
};
@usesDataProvider myDataProvider
test('test_isPetitionActive_calledWithParams_returnCorrectAnswer', function (expected, date) {
exerciseIsPetitionActive(expected, date);
});
var myDataProvider = function() {
return {
{true, new Date(..)},
{false, new Date(...)}
};
};
То, что я уже рассмотрел
Существует несколько tecnique, которые называются Общие действия. Но он не решает проблему напрямую с помощью тестового набора, он просто решает проблему с разными компонентами, которые имеют дублированные тесты.
Вопрос
Знаете ли вы какой-либо способ реализовать dataProviders в мокко?
Ответы
Ответ 1
Mocha не предоставляет для этого инструмента, но легко сделать это сам. Вам нужно всего лишь запустить тесты внутри цикла и передать данные в тестовую функцию с помощью закрытия:
suite("my test suite", function () {
var data = ["foo", "bar", "buzz"];
var testWithData = function (dataItem) {
return function () {
console.log(dataItem);
//Here do your test.
};
};
data.forEach(function (dataItem) {
test("data_provider test", testWithData(dataItem));
});
});
Ответ 2
Базовый подход для запуска одного и того же теста с разными данными заключается в повторении теста в цикле, предоставляющем данные:
describe('my tests', function () {
var runs = [
{it: 'options1', options: {...}},
{it: 'options2', options: {...}},
];
before(function () {
...
});
runs.forEach(function (run) {
it('does sth with ' + run.it, function () {
...
});
});
});
before
пробегает, ну, перед всеми it
в describe
. Если вам нужно использовать некоторые из параметров в before
, не включайте его в цикл forEach
, потому что mocha сначала будет запускать все before
и все it
s, что, вероятно, не нужно. Вы можете поместить целое describe
в цикл:
var runs = [
{it: 'options1', options: {...}},
{it: 'options2', options: {...}},
];
runs.forEach(function (run) {
describe('my tests with ' + run.it, function () {
before(function () {
...
});
it('does sth with ' + run.it, function () {
...
});
});
});
Если вы не хотите загрязнять свои тесты несколькими describe
s, вы можете использовать спорный модуль sinon
для этого:
var sinon = require('sinon');
describe('my tests', function () {
var runs = [
{it: 'options1', options: {...}},
{it: 'options2', options: {...}},
];
// use a stub to return the proper configuration in `beforeEach`
// otherwise `before` is called all times before all `it` calls
var stub = sinon.stub();
runs.forEach(function (run, idx) {
stub.onCall(idx).returns(run);
});
beforeEach(function () {
var run = stub();
// do something with the particular `run.options`
});
runs.forEach(function (run, idx) {
it('does sth with ' + run.it, function () {
sinon.assert.callCount(stub, idx + 1);
...
});
});
});
Синон чувствует себя грязным, но эффективен. Несколько модулей помощи, таких как leche, основаны на синоне, но, возможно, введение дополнительной сложности не требуется.
Ответ 3
Leche добавляет эту функцию в Mocha. См. объявление и docs.
Лучше, чем просто перебирать тесты, потому что, если тест не удается, он сообщает вам, какой набор данных был задействован.
Update:
Мне не понравилась настройка Leche, и мне не удалось заставить ее работать с кармой, поэтому в итоге я извлек поставщика данных в отдельный файл.
Если вы хотите использовать его, просто захватить источник. Документация доступна в Leche readme, и вы найдете дополнительные сведения и советы по использованию в самом файле.
Ответ 4
Основываясь на ответе @Kaizo, вот что я придумал для своего теста (это контроллер, который получает некоторые параметры из запроса) для эмуляции поставщика данных в PHPUnit. Метод getParameters
будет получать запрос от Express, а затем использовать req.param
для проверки некоторых параметров запроса, например, GET /jobs/?page=1&per_page=5
. Это также показывает, как заглушить объект запроса Express.
Надеюсь, это тоже поможет кому-то.
// Core modules.
var assert = require('assert');
// Public modules.
var express = require('express');
var sinon = require('sinon');
// Local modules.
var GetJobs = require(__base + '/resources/jobs/controllers/GetJobs');
/**
* Test suite for the `GetJobs` controller class.
*/
module.exports = {
'GetJobs.getParameters': {
'should parse request parameters for various cases': function () {
// Need to stub the request `param` method; see http://expressjs.com/3x/api.html#req.param
var stub = sinon.stub(express.request, 'param');
var seeds = [
// Expected, page, perPage
[{limit: 10, skip: 0}],
[{limit: 5, skip: 10}, 3, 5]
];
var controller = new GetJobs();
var test = function (expected, page, perPage) {
stub.withArgs('page').returns(page);
stub.withArgs('per_page').returns(perPage);
assert.deepEqual(controller.getParameters(express.request), expected);
};
seeds.forEach(function (seed) {
test.apply({}, seed);
});
}
}
};
Единственным недостатком является то, что Mocha не учитывает фактические утверждения (например, PHPUnit), это просто показывает один тест.