用Sinon.js伪造一个模拟方法

时间:2016-03-15 16:55:30

标签: javascript unit-testing sinon buster.js

我在使用Sinon.js和Buster.js测试时使用模拟替换我的类的依赖项时遇到了麻烦。

我正在测试B类,它依赖于A类。我使用Sinon.js创建A类的模拟对象,并将其传递给B类的实例。在我的测试中,我调用了对象B的doSomething方法,然后调用对象A的getData方法。(虽然getData方法实际上是A的原型,而不是A本身。)

但是当我运行测试时,我得到错误:

TypeError: a.getData is not a function

如果我尝试并保留A&#39}原型的getData方法,那么我会收到错误:

TypeError: Attempted to wrap getData which is already stubbed

错误发生在我设置mock_A.expects('getData')的行上。 这是我正在运行的课程和测试:

function A(){};
A.prototype = {
    "getData" : function(oDataToGet, cb) {
        var aData = ['someData'];
        cb(aData);
    }
}
function B() {
    var a;
    this.setA = function(oA){
        a = oA;
    };
    this.doSomething = function(oObj){
        a.getData({}, function(aData){if(!aData){throw new Error('No data');} oObj.data = aData[0];});
    }
}


var oB, assert = buster.referee.assert;
buster.testCase('myTest', {
    "setUp" : function()
    {
        oB = new B();
    },
    "test_Mock" : function()
    {
        var mock_A = sinon.mock(new A());
            oB.setA(mock_A);
    //        sinon.stub(A.prototype, 'getData').callsArgWith(1, ['hi']);
        mock_A.expects('getData')
            .withArgs({})
            .once();
        var oTestObj = {};
        oB.doSomething(oTestObj)
        mock_A.verify();
    }
});

编辑2016-03-16添加: 解决方法是使用存根实例而不是模拟,然后设置需要检查的方法:

var stubbed_A = sinon.createStubInstance(A);
stubbed_A.getData = sinon.expectation.create('getData')
    .withArgs({})
    .once();
oB.setA(stubbed_A);
var oTestObj = {};
oB.doSomething(oTestObj);
stubbed_A.getData.verify();

1 个答案:

答案 0 :(得分:0)

sinonJS与其他模拟框架(如Mockito,jMock等)之间存在差异,造成了这种误解。在大多数模拟框架中,您创建模拟的依赖项并将其注入要测试的对象(SUT)中,如下所示:

var mock_A = sinon.mock(new A());
oB.setA(mock_A);

但是,在sinonJS中,您必须注入原始对象并使用生成的模拟对象来分配对原始对象的期望。因此,如果您使用以下内容更改前两行,则测试将按预期工作:

var a = new A();
var mock_A = sinon.mock(a);
oB.setA(a);

当我们想要控制我们正在测试的对象的依赖关系的行为时,存根更合适。当我们想要确保特定事件将发生在我们正在测试的对象(通过期望)的依赖性时,模拟更合适。因此,在这种情况下,模拟对象比存根更合适,就像你第一次尝试一样。