Подтвердить что ты не робот

Выполнение одного и того же теста мокки несколько раз с разными данными

Проблема

У меня есть несколько тестов, которые делают то же самое в мокко. Это для меня, это дублирование, и это худшее, что нужно сделать, когда вы хотите, чтобы ваша система была поддающейся поддержке.

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

Что мне нужно

Мне нужен способ свернуть мои дублированные тесты мокко только в одном.

Например, в 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(...)}
  };
};

То, что я уже рассмотрел

Существует несколько tecnique, которые называются Общие действия. Но он не решает проблему напрямую с помощью тестового набора, он просто решает проблему с разными компонентами, которые имеют дублированные тесты.

Вопрос

Знаете ли вы какой-либо способ реализовать dataProviders в мокко?

4b9b3361

Ответ 1

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

Ответ 2

Базовый подход для запуска одного и того же теста с разными данными заключается в повторении теста в цикле, предоставляющем данные:

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 пробегает, ну, перед всеми it в describe. Если вам нужно использовать некоторые из параметров в before, не включайте его в цикл forEach, потому что mocha сначала будет запускать все before и все it s, что, вероятно, не нужно. Вы можете поместить целое 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 s, вы можете использовать спорный модуль 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, основаны на синоне, но, возможно, введение дополнительной сложности не требуется.

Ответ 3

Leche добавляет эту функцию в Mocha. См. объявление и docs.

Лучше, чем просто перебирать тесты, потому что, если тест не удается, он сообщает вам, какой набор данных был задействован.

Update:

Мне не понравилась настройка Leche, и мне не удалось заставить ее работать с кармой, поэтому в итоге я извлек поставщика данных в отдельный файл.

Если вы хотите использовать его, просто захватить источник. Документация доступна в Leche readme, и вы найдете дополнительные сведения и советы по использованию в самом файле.

Ответ 4

Основываясь на ответе @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), это просто показывает один тест.