Many frameworks use the word “mock” for what in reality are “spies”. But that’s OK, the work “mock” in English covers actually all the possible test double types…
However according to G. Meszaros, a mock object is a specific type of test double that is configured with expectations before exercising the system under test. During the execution the mock compares the calls being made, to its expectations failing if they don’t match.
The two frameworks I use for test doubles in JavaScript are Jasmine and Sinon.js. And I also use some helpers of my own. None of these two frameworks provide actual mock objects. Sinon has a “mock” function that let us configure expectations before exercising the system under test. It behaves like a mock if we are working with functions only. Nonetheless if we are working with objects (OOP), then what Sinon provides is not a mock object because a call to any other method in the object other than the expected, will not fail the test. And it should as unexpected calls should make the test fail.
The solution to have real mock objects with Sinon is just a little helper:
//------ HELPER FUNCTIONS
function unexpectedCall(functName)
{
return function(){
throw new Error('Function ' + functName + ' was not expected but invoked');
};
}
function inocuousCall(){
return function(){};
}
function replaceAll(obj){
return {
methodsWith: function(fn){
for (var propName in obj)
if (typeof(obj[propName]) == 'function')
obj[propName] = fn(propName);
}
}
}
function stubThe(obj){
replaceAll(obj).methodsWith(inocuousCall);
}
function mockThe(obj){
replaceAll(obj).methodsWith(unexpectedCall);
}
//------ THE TEST
it("stores the user when adding a new one", function(){
// the DOC (depended-on component)
var repo = userRepository();
// the SUT (system under test) and dependency injection
var service = userService(repo);
// patching the DOC, making it a mock
mockThe(repo);
var mock = sinon.mock(repo);
// configuring expectation:
mock.expects("store").once();
// exercising the SUT
service.add(new User({email: 'test@test.com'}));
// verifying configured expectations
mock.verify();
});
In languages like Java or C#, test doubles frameworks create a replacement for all the methods in the target class/interface. In JavaScript however, frameworks replace single functions. For this reason it’s possible to have the same object acting as the SUT and the double in a single test. But the fact it’s possible doesn’t mean it’s right. Whenever you find yourself in a test using a double for some method and then invoking another method in the same object, think carefully whether the design is appropriate. That smell is usually pointing out that you should extract a new class and create a dependency between the old and the new, so that one acts as the double and the other as the SUT.