使用不同的数据多次运行相同的mocha测试

时间:2013-06-17 09:21:46

标签: javascript mocha

问题

我有几个测试在mocha中做同样的事情。这对我而言,它是重复的,当您希望系统可以维护时,这是最糟糕的事情。

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

我需要什么

我需要一种方法来将我的重复mocha测试折叠成一个。

例如,在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)
        );
    }
}

此处的提供程序将参数注入测试,测试执行所有情况。非常适合重复测试。

我想知道在mocha中是否存在类似的东西,例如:

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

我已经看过

有一些名为Shared Behaviours的tecnique。但它并没有直接用测试套件解决问题,只是解决了具有重复测试的不同组件的问题。

问题

您知道在mocha中实现dataProviders的方法吗?

6 个答案:

答案 0 :(得分:21)

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

答案 1 :(得分:18)

使用不同数据运行相同测试的基本方法是在提供数据的循环中重复测试:

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 () {
      ...
    });
  });
});
嗯,beforeit中的所有describe之前运行。如果您需要使用before中的某些选项,将其包含在forEach循环中,因为mocha将首先运行所有before和所有it 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

如果您不希望使用多个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); ... }); }); }); 来解决此问题:

 $scope.removeChoice = function(parent_id,id) {       

    var TempArr=[];
    var parentLength=$scope.choices[parent_id].length;
    for(i=0;i<parentLength;i++ ){
        if(parentLength[i]!==id){
            TempArr.push(parentLength[i]);
        }
        if(i==parentLength-1){
             $scope.choices[parent_id]=[];
            $scope.choices[parent_id]=TempArr;
        }
    }
 };

诗乃感觉很脏但很有效。像leche这样的一些辅助模块是基于sinon的,但可以说引入更多复杂性是没有必要的。

答案 2 :(得分:3)

Leche将该功能添加到Mocha中。请参阅announcementdocs

这比简单地循环测试更好,因为如果测试失败,它会告诉你涉及哪个数据集。

<强>更新

我不喜欢Leche的设置并且没有设法让它与Karma一起工作,所以最终我将数据提供程序提取到separate file

如果您想使用它,只需grab the source。文档可用in the Leche readme,您可以在文件中找到其他信息和使用提示。

答案 3 :(得分:2)

根据@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那样),它只是显示为一个测试。

答案 4 :(得分:0)

下面使用mocha-testdata库描述了一个更简单的解决方案。

问题的示例解决方案。

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

如果您需要测试node.js应用中最常见的异步函数调用,请改用givenAsync。

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

答案 5 :(得分:0)

我发现mocha-testcheck是最简单的工具。它生成各种数据。它将缩小导致测试失败的输入。