Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running the same mocha test multiple times with different data

Problem

I have several tests that do the same thing in mocha. This for me, it's duplication, and is the worst thing to do when you want your system to be 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')); }); 

What do I need

I need a way of collapsing my duplicated mocha tests in only one.

For example, in PhpUnit (and other test frameworks) you have dataProviders.
In phpUnit a dataProvider works this way:

<?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)         );     } } 

The provider in here injects parameters to the test, and the test executes all the cases. Is perfect for duplicated test.

I want to know if in mocha is there something similar, for example, something like this:

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(...)}   }; }; 

What I have already looked at

There is some tecnique that is called Shared Behaviours . But it does not solve the problem directly with a test suite, it just solve the problem with different components that have duplicated tests.

The Question

Do you know any way to implement dataProviders in mocha?

like image 301
Tomás Avatar asked Jun 17 '13 09:06

Tomás


People also ask

Do Mocha tests run sequentially?

Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases.

Does Mocha run tests in parallel?

Mocha does not run individual tests in parallel. That means if you hand Mocha a single, lonely test file, it will spawn a single worker process, and that worker process will run the file. If you only have one test file, you'll be penalized for using parallel mode. Don't do that.

How do I run a specific test in Mocha?

Learn how to run only one test with Mocha To run a single test (as defined in it() ), you can simply call the only() method on it in the following way: it. only('...', function () { // only this test will run... });

What is beforeEach in Mocha?

The beforeEach method is a feature (hook) in test libraries that you can use to set preconditions for each test. Just like the name suggests, it runs before each test in your test suite. For example, the beforeEach method will run four times in a suite with four tests.


2 Answers

A basic approach to run the same test with different data is to repeat the test in a loop providing the data:

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 runs, well, before all its in a describe. If you need to use some of the options in before, do not include it in the forEach loop because mocha will first run all befores and the all its, which is probably not wanted. You can either put the whole describe in the loop:

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 () {       ...     });   }); }); 

If you do not wish to pollute your tests with multiple describes, you can use the controversial module sinon for this matter:

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 feels dirty but is effective. Several aid modules such as leche are based on sinon, but arguably introducing further complexity is not necessary.

like image 160
Wtower Avatar answered Sep 19 '22 00:09

Wtower


Mocha doesn't provide a tool for that, but it is easy to do it yourself. You only need to run the tests inside a loop and give the data to the test function using a closure:

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));     }); }); 
like image 37
Kaizo Avatar answered Sep 20 '22 00:09

Kaizo