在单元测试中重置模块

Reset module in unit tests

本文关键字:模块 单元测试      更新时间:2023-09-26

我有一个使用以下模式创建的requirejs模块:

// foo.js
define(function(){
    var x = 0;
    function doStuff(){
        return ++x;
    }
    return { doStuff: doStuff };
});

还有一个 QUnit 测试,看起来像这样:

// testfoo.js
define(['QUnit, foo'], function(QUnit, foo){
    function setup(){
        //...?
    }        
    function teardown(){
       //...?
    }
    function runTests(){
         QUnit.test('foo counter remains at 1 on multiple tests', function(assert){
              assert.equal(foo.doStuff(), 1); // this will work
         });
         QUnit.test('foo counter remains at 1 on multiple tests', function(assert){
              assert.equal(foo.doStuff(), 1); // this obviously won't
         });
     }
     return runTests;
});

如何重置每个测试的foo

我想保留foo揭示模块,即不将其转换为具有更改原型的构造函数。

我尝试了var foo = require('foo');,但由于requirejs是基于AMD的,它会抱怨东西以错误的顺序加载。

我建议查看SquireJS为您的测试创建一个隔离的上下文。 Squire 旨在通过创建隔离的 RequireJS 上下文来注入模拟依赖项。 这样做的副作用是,每次调用 injector.require() 时都会重新加载 'foo' 库,重置库的状态。 唯一的缺点是您的测试需要是异步的。

// testfoo.js
define(['Squire', 'foo'], function (Squire, foo) {
 'use strict';
  QUnit.start();
  QUnit.module('foo', {
    setup: function () {
    },
    teardown: function () {
    }
  });
  QUnit.test('Testing foo counter in main context.', 2, function (assert) {
    assert.equal(foo.doStuff(), 1); // this will work
    assert.equal(foo.doStuff(), 2); // this should work also.
  });
  QUnit.test('Testing foo counter in context created by Squire.', 1, function (assert) {
    var done = assert.async(),
      injector = new Squire();
    injector.require([
      'foo'
    ], function (foo) {
      assert.equal(foo.doStuff(), 1); // this will work.
      done();
    });
  });
});

我在这里发布了一个示例项目:qunit-squirejs

虽然这肯定不是最干净的方法,但通过将函数保存为字符串,并在每次测试之前重新创建函数,您可以实现相同的效果。

var fooString = foo.toString();
QUnit.testStart(function() { eval('foo = ' + fooString});