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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17144197/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 07:15:02  来源:igfitidea点击:

Running the same mocha test multiple times with different data

javascriptmocha

提问by Tomas Prado

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.

我有几个测试在 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'));
});

What do I need

我需要什么

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

我需要一种方法将重复的 mocha 测试合并为一个。

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

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

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?

你知道在 mocha 中实现 dataProviders 的任何方法吗?

采纳答案by Kaizo

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:

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

回答by Wtower

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

beforeruns, well, before all its in a describe. If you need to use some of the options in before, do notinclude it in the forEachloop because mocha will first run all befores and the all its, which is probably not wanted. You can either put the whole describein the loop:

beforeit在 a 中的所有s之前运行describe。如果您需要使用 中的某些选项before请不要将其包含在forEach循环中,因为 mocha 将首先运行 all befores 和 all its,这可能不是我们想要的。您可以将整个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 () {
      ...
    });
  });
});

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

如果你不想用多个describes污染你的测试,你可以使用有争议的模块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);
      ...
    });
  });
});

Sinon feels dirty but is effective. Several aid modules such as leche are based on sinon, but arguably introducing further complexity is not necessary.

诗乃感觉脏,但很有效。一些辅助模块(例如 leche)基于 sinon,但可以说没有必要引入进一步的复杂性。

回答by hashchange

Lecheadds that functionality to Mocha. See the announcementand docs.

Leche将该功能添加到 Mocha。请参阅公告文档

It is better than simply looping over the tests because, if a test fails, it tells you which data set was involved.

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

Update:

更新:

I didn't like the setup of Leche and haven't managed to get it to work with Karma, so eventually I have extracted the data provider into a separate file.

我不喜欢 Leche 的设置,也没有设法让它与 Karma 一起工作,所以最终我将数据提供者提取到一个单独的文件中

If you want to use it, just grab the source. Documentation is available in the Leche readme, and you'll find additional info and usage tips in the file itself.

如果你想使用它,只需抓住源代码Leche 自述文件中提供文档,您可以在文件本身中找到其他信息和使用技巧。

回答by Andrew Eddie

Based on the @Kaizo's answer, here's what I came up with for my test (it's a controller that is getting some parameters from the request) to emulate the data provider in PHPUnit. The getParametersmethod is going to receive the request from Express, and then use req.paramto inspect some query parameters, for example, GET /jobs/?page=1&per_page=5. This also shows how to stub the Express request object.

基于@Kaizo 的回答,这是我为我的测试(它是一个从请求中获取一些参数的控制器)想出的来模拟 PHPUnit 中的数据提供者。该getParameters方法将接收来自 Express 的请求,然后用于req.param检查一些查询参数,例如GET /jobs/?page=1&per_page=5. 这也展示了如何存根 Express 请求对象。

Hopefully it can help someone as well.

希望它也可以帮助某人。

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

The only downside is Mocha doesn't count the actual assertions (like PHPUnit does), it just shows up as one test.

唯一的缺点是 Mocha 不计算实际的断言(就像 PHPUnit 一样),它只显示为一个测试。

回答by Chandana Kithalagama

A simpler solution is described below using mocha-testdatalibrary.

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

Sample solution to the problem.

问题的示例解决方案。

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

If you need to test async function calls which is the most common case in node.js app, use givenAsync instead.

如果您需要测试异步函数调用,这是 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();
    });
  });
});

回答by Zachary Ryan Smith

I've found mocha-testcheckto be the easiest tool for this. It generates all kinds of data. It will narrow down which input is causing your test to fail.

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