如何确保测试对象属性的更改不会传播到其他测试用例?

时间:2014-10-31 10:04:58

标签: node.js testing mocha

这是foo.js

var Foo;

Foo = function () {
    var foo = {};
    foo.get = function (url) {
        // [..]
        return Foo.get(url);
    };
    return foo;
};

Foo.get = function (url) {};

module.exports = Foo;

这是foo.js的测试用例:

var expect = require('chai').expect,
    sinon = require('sinon');

describe('foo', function () {
    var Foo,
        foo;
    beforeEach(function () {
        Foo = require('foo.js');
        foo = Foo();
    });
    describe('.get(url)', function () {
        it('passes the call to Foo.get(url)', function () {
            var spy = sinon.spy();

            // We are going to spy on Foo.get:
            Foo.get = spy;

            foo.get('http://');
            // [..]
        });
        it('does something else', function () {
            foo.get('http://');

            // Here Foo.get persists to refer to an instance of sinon.spy.
            // How to make sure that the tests are indepeondent?
        });
    });
});

我已覆盖Foo.get属性以窥探它。

我希望使用beforeEachrequire('foo.js')会覆盖Foo对象,并使下一个测试不知道对象的先前更改。

显而易见的解决方案是存储对先前属性状态的引用并在测试后将其恢复,例如

it('passes the call to Foo.get(url)', function () {
    var spy = sinon.spy(),
        Fooget = Foo.get;

    // We are going to spy on Foo.get:
    Foo.get = spy;

    foo.get('http://');
    // [..]

    Foo.get = Fooget;
});

但是,这种方法容易出错。

这样做的一种方法是重写模块&把它变成一个构造函数:

module.exports = function () {
    var Foo;

    Foo = function () {
        var foo = {};
        foo.get = function (url) {
            // [..]
            return Foo.get(url);
        };
        return foo;
    };

    Foo.get = function (url) {};
};

然后在每次测试之前构造一个新实例:

describe('foo', function () {
    var Foo,
        foo;
    beforeEach(function () {
        Foo = require('foo.js')();
        foo = Foo();
    });
    describe('.get(url)', function () {
        // [..]
    });
});

虽然不太理想,因为这会影响库的API。

1 个答案:

答案 0 :(得分:1)

因此,sinon已经恢复了内置的间谍/存根/模拟。最好让sinon自行清理,而不是尝试手动实现自己的清理代码。使用mocha,甚至可以mocha-sinon为您进行清理。 mocha-sinon文档还解释了如何使用sinon沙箱来跟踪需要清理和清理的内容,但是如果你使用mocha-sinon并在你的mocha测试代码中做this.sinon,那么沙箱创建和清理会自动发生。

var sinon = require('sinon');

beforeEach(function() {
  this.sinon = sinon.sandbox.create();
});

afterEach(function(){
  this.sinon.restore();
});