简体   繁体   中英

Stubbing a mock's method with Sinon.js

I'm having trouble using a mock to replace a dependency of my class when testing, using Sinon.js and Buster.js.

I'm testing class B, which has a dependency on class A. I use Sinon.js to create a mock object of class A, and pass it into an instance of class B. In my test I call the doSomething method of object B, which then calls the getData method of object A. (Though the getData method is actually on A's prototype, not A itself).

But when I run the test I get the error:

TypeError: a.getData is not a function

If I try and stub the getData method of A's prototype, then I get the error:

TypeError: Attempted to wrap getData which is already stubbed

The error occurs on the line where I'm setting mock_A.expects('getData') . This is the classes and test I'm running:

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

Edit 2016-03-16 to add: A workaround is to use a stubbed instance rather than a mock, and then set the method you need to check to an expectation:

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

There is a difference between sinonJS and other mocking frameworks (like Mockito, jMock etc.) that creates this misunderstanding. In most mocking frameworks, you create the mocked dependency and inject it in the object-to-be-tested (SUT), as you did:

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

However, in sinonJS, you have to inject the original object and use the generated mock object to assign expectations over the original one. So, if you change the previous 2 lines with the following, your test works as expected:

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

Stubs are more appropriate, when we want to control the behaviour of a dependency of the object we are testing. Mocks are more appropriate, when we want to ensure that a specific event will happen on the dependency of the object we are testing (via expectations). So, in this case, a mock object would be more suitable than a stub, as in your first attempt.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM