Exécution du même test mocha plusieurs fois avec des données différentes
Problème
j'ai plusieurs tests qui font la même chose en moka. Pour moi, c'est la duplication, et c'est la pire chose à faire lorsque vous voulez que votre système soit maintenable.
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'));
});
Que dois-je
j'ai besoin d'un moyen de faire s'effondrer mes tests de moka dupliqués en un seul.
par exemple, dans PhpUnit (et d'autres cadres de test) vous avez fournisseurs de données.
Dans phpUnit un dataProvider fonctionne de cette façon:
<?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)
);
}
}
le fournisseur injecte ici des paramètres au test, et le test exécute tous les cas. Est parfait pour le test dupliqué.
je veux savoir si dans le moka est-il quelque chose de similaire, par exemple, quelque chose comme ceci:
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(...)}
};
};
Ce que j'ai déjà regardé
Il y a quelques tecnique qui est appelé Comportements Partagés . Mais il ne résout pas le problème directement avec une suite de test, il vient de résoudre le problème avec différents composants qui ont dupliqué les tests.
La Question
connaissez-vous un moyen d'implémenter des fournisseurs de données dans mocha?
6 réponses
Moka ne fournit pas d'outil pour cela, mais il est facile de le faire vous-même. Il suffit d'exécuter les tests à l'intérieur d'une boucle et de donner les données à la fonction test en utilisant une fermeture:
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));
});
});
une approche de base pour exécuter le même test avec des données différentes est de répéter le test dans une boucle fournissant les données:
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
fonctionne, bien, avant tout it
s:describe
. Si vous avez besoin d'utiliser certaines options dans before
,ne pas l'inclure dans le forEach
boucle parce que mocha va d'abord courir tout before
s et it
s, qui n'est probablement pas voulu. Vous pouvez soit mettre l'ensemble de l' describe
dans la boucle:
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 () {
...
});
});
});
Si vous ne souhaite pas polluer vos tests avec plusieurs describe
s, vous pouvez utiliser le controversé module sinon
pour cette question:
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);
...
});
});
});
Sinon se sent sale, mais est efficace. Plusieurs modules d'aide tels que leche sont basés sur le sinon, mais il est permis de penser qu'il n'est pas nécessaire d'introduire davantage de complexité.
Leche ajoute cette fonctionnalité à Mocha. Voir le annonce et docs.
c'est mieux que de simplement faire une boucle au-dessus des tests parce que, si un test échoue, il vous dit quel ensemble de données a été impliqué.
mise à Jour:
Je n'ai pas aimé la configuration de Leche et n'ai pas réussi à la faire fonctionner avec Karma, donc finalement j'ai extrait le fournisseur de données dans un fichier séparé.
Si vous voulez l'utiliser, il suffit saisir la source. La Documentation est disponible dans le Leche readme, et vous pourrez trouver des informations supplémentaires et conseils d'utilisation dans le fichier lui-même.
basé sur la réponse de @Kaizo, voici ce que j'ai trouvé pour mon test (c'est un contrôleur qui reçoit quelques paramètres de la requête) pour émuler le fournisseur de données dans PHPUnit. getParameters
method va recevoir la requête D'Express, puis utiliser req.param
pour inspecter certains paramètres de la requête, par exemple, GET /jobs/?page=1&per_page=5
. Cela montre aussi comment couper L'objet Requête Express.
espérons que cela puisse aussi aider quelqu'un.
// 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);
});
}
}
};
le seul inconvénient est Moka ne compte pas les affirmations réelles (comme le fait PHPUnit), il apparaît juste comme un test.
une solution plus simple est décrite ci-dessous en utilisant moka-testdata bibliothèque.
exemple de solution au problème.
import * as assert from assert;
import { givenAsync } from mocha-testdata;
suite('My async test suite', function () {
given([0, 0, 0], [0, 1, 1], [1, 0, 1], [1, 1, 3]).test('sum to 6', function (a, b, c) {
assert.strictEqual(a + b + c, 6);
});
});
si vous avez besoin de tester les appels de fonction async qui est le cas le plus commun dans le noeud.js app, utilisez givenAsync à la place.
import * as assert from assert;
import { givenAsync } from mocha-testdata;
suite('My async test suite', function () {
givenAsync([1, 2, 3], [3, 2, 1]).test('sum to 6', function (done, a, b, c) {
doSomethingAsync(function () {
assert.strictEqual(a + b + c, 6);
done();
});
});
});
j'ai trouvé moka-testcheck pour être l'outil le plus simple pour cela. Il génère des données de toutes sortes. Il permet de réduire le nombre d'entrées qui causent l'échec de votre test.