61

問題

モカで同じことを行ういくつかのテストがあります。私にとってこれは重複であり、システムを保守可能にしたい場合に行うのは最悪のことです。

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

私が必要なものは何

重複したモカ テストを 1 つだけに折りたたむ方法が必要です。

たとえば、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)
        );
    }
}

ここのプロバイダーはパラメーターをテストに挿入し、テストはすべてのケースを実行します。重複テストに最適です。

モカに似たようなものがあるかどうか知りたいです。たとえば、次のようなものです。

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 Behaviorsと呼ばれるテクニックがあります。ただし、テスト スイートで問題を直接解決するのではなく、テストが重複しているさまざまなコンポーネントで問題を解決するだけです。

質問

モカで dataProviders を実装する方法を知っていますか?

4

6 に答える 6

36

異なるデータで同じテストを実行する基本的な方法は、データを提供するループでテストを繰り返すことです。

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まあ、 a のすべての の前に実行されdescribeます。のオプションの一部を使用する必要がある場合は、ループに含めないbeforeでください。これは、 mocha がまずすべての とすべての を実行するためです。これはおそらく望ましくありません。全体をループに入れることができます:forEachbeforeitdescribe

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

シノンは汚く感じるが効く。leche などのいくつかの援助モジュールは sinon に基づいていますが、おそらくさらに複雑にする必要はありません。

于 2016-09-02T07:23:57.997 に答える
34

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));
    });
});
于 2013-06-26T09:26:18.150 に答える
5

Lecheはその機能を Mocha に追加します。お知らせドキュメントを参照してください。

テストが失敗した場合に、どのデータ セットが関係しているかがわかるため、単純にテストをループするよりも優れています。

アップデート:

Leche の設定が気に入らなかったので、Karma と連携させることができなかったので、最終的にデータ プロバイダーを別のファイルに抽出しました。

使いたい場合は、ソースを入手してください。ドキュメンテーションはLeche readmeで入手でき、ファイル自体に追加情報と使用上のヒントが記載されています。

于 2014-12-02T13:19:28.053 に答える
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 のように) 実際のアサーションをカウントせず、1 つのテストとして表示されることです。

于 2014-06-13T00:44:54.930 に答える