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?

35
demandé sur Tomas Prado 2013-06-17 13:21:45

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));
    });
});
20
répondu Kaizo 2013-06-26 09:26:18

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 its: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 befores et its, 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 describes, 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é.

10
répondu Wtower 2016-09-02 07:23:57

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.

3
répondu hashchange 2015-02-20 12:31:36

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.

2
répondu Andrew Eddie 2014-06-13 00:44:54

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();
    });
  });
});
0
répondu Chandana Kithalagama 2018-01-11 22:19:17

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.

0
répondu Zachary Ryan Smith 2018-02-08 02:31:03