sinon spy not detecting a function call - javascript

I'm trying to use sinonJS framework for nodeJS unit tests. The problem is, I cannot get the sinon spies working at all. This is my code:
const callback = sinon.spy(someModule.callback)
mainModule.doSomethingFunction() //someModule.callback function is called inside this function
assert(callback.calledOnce, 'callback should be called once')
It just fails with:
AssertionError: callback should be called once
But I'm logging inside the function that should be called, and it clearly shows it is being called, the sinon spies just doesn't detect it. I wonder what is wrong?

To wrap an object method in a spy, you can use sinon like this:
const callback = sinon.spy(someModule, 'callback');
mainModule.doSomethingFunction();
assert(callback.calledOnce, 'callback should be called once');
callback.restore();
Note that you should call restore when you are done to unwrap the spy.

The statement const callback = sinon.spy(someModule.callback) creates a spy that will call the someModule.callback once it is called (BTW it is not a constant) but it doesn't replace the someModule.callback function. To replace the function use someModule.callback = sinon.spy(someModule.callback)

Related

Sinon stubbed method no longer stubbed when using underscore delay

So I'm writing javascript unit test using sinon stubs. The stubbed method is called in the code is wrapped in a delay (underscore delay). However, the actual method is getting called rather than the stub. When I don't use delay, it works as expected and calls the stub. I've included an example below of what the code looks like. Any idea what might be going on? One hypothesis I have is that sinon is keeping track of references of someObject to restore the stub, and since I'm using a delay, someObject falls out of scope and the stub is restored to the actual method.
// This is code form the unit test.
// someObject.someFunction is stubbed
sinon.stub(someObject, 'someFunction', function() {
console.log('stubbed someFunction');
});
someObject.execute();
// These methods are defined within someObject
execute: function() {
_.delay(
function() {
this.someFunction();
},
1000
);
}
// This is called from the unit test despite being stubbed.
// However, when the _.delay() is removed, the stubbed
// method is called.
someFunction: function() {
console.log('real someFunction');
}

Returning a sinon stub from a sinon stub

I have problems getting a sinon stub to return/resolve another sinon stub. I am using sinon, chai, chai-as-promised and mocha.
I am performing a number of async tasks in sequence and the code I want to test look something like this:
Terminal.findOneAsync({terminalId: terminalId}).then(function(terminal) {
terminal.lastSeen = timestamp;
return terminal.saveit();
}).then(function(terminal) {
//continue to do other stuff
});
And my attempt at creating stubs for this look like this:
var saveitStub = sinon.stub(Terminal.prototype, 'saveit');
saveitStub.resolves(terminalUpdated);
var findOneStub = sinon.stub(Terminal, 'findOneAsync');
findOneStub.resolves(saveitStub);
The "saveit" method is in the Terminal.prototype which is why I need to stub it there.
When I attempt to run this I get the error:
Unhandled rejection TypeError: undefined is not a function
at the line:
return terminal.saveit();
But if I dump the terminal object out in the console it looks fine, just like any other stub object (at least to my simple mind). The stubbed saveit() method can be called "stand alone" in a test. But whenever I return it through chai's "return" or chai-as-promised's "resolve" methods I get this error.
Any idea why this is the case?
This line:
findOneStub.resolves(saveitStub)
Is causing Terminal.findOneAsync to return a stub function, not a Terminal instance. Obviously, the stub function has no property called saveit, even though Terminal.prototype does. Since unknown properties come back as undefined, this winds up with you attempting to invoke undefined as a function.
To make a test like this, you're probably better off constructing an instance of Terminal and stubbing its saveit method. If constructing an instance is too difficult for whatever reason, you can use sinon.createStubInstance. Since I don't know your constructor's signature I'll go ahead and do that as an example:
var terminal = sinon.createStubInstance(Terminal);
var saveitStub = terminal.saveit
saveitstub.resolves(terminalUpdated)
var findOneStub = sinon.stub(Terminal, 'findOneAsync')
findOneStub.resolves(terminal);

Jasmine junit testing of delegate callback of function args

I have recently started using jasmine to write junit testcase for one of our application.
I am stuck at this point on how to call the callBack function of the spied function.
setProfile :function(userProfile,callback){
var user;
var subjectInfo;
iService.searchForAccess(subjectInfo , queryCalback);
function queryCalback(err, userProfile) {
if(err){
callback(true,errorMessage)
}else{
callback(false,null)
}
}
}
Now in my spec i want to mock the call to iService.searchForAccess real world implementation and want to call nocallThrough for searchForAccess . but my queryCalback function has to be called for complete use case coverage.
In my spec i have tried to call queryCalback function explicitly by
spyOn(iService,'searchForAccess');
iService.searchForAccess.mostRecentCall.args[1](error, userProfile);
but iService.searchForAccess.mostRecentCall returns {}, empty object.
kindly help!!!!!!!!!!
Regards
Punith
I have used sinonjs as solution to above problem statement. Below is the syntax of how its done.
var sinon = require('../node_modules/sinon/lib/sinon.js');
sinon.stub(iService, 'searchForAccess').callsArgWith(1, mockSubjectInfo, session.userProfile);
Hope it will be helpfull to others.
Regards
Punith

Asserting that a callback has been passed with the correct scope

I'm trying to find a way to test that ObjectA is correctly setting up a callback from ObjectB to ObjectC.
e.g.
// In class (has scope issue)
this._processor.process('stuff', this._handler.handle);
// In test
expect(processor.process).toHaveBeenCalledWith('stuff', handler.handle);
What I went to test is that the following call actually takes place:
this._processor.process('stuff', this._handler.handle.bind(this._handler));
I'm aware I can fix this by handling the callback like so:
this._processor.process('stuff', function() {
this._handler.handle()
});
And testing that the 'handler' spy gets called on callback from the process function (this is how I'm generally doing things at the moment). But setting it all up makes the test messy and adds code and complexity to the class under test purely to make it testable.
In the general sense, each call to a spy tracks the scope in the object property (assuming Jasmine 1.3):
it("has the right scope", function () {
var scopeObj = {foo: "bar"};
var spy = jasmine.createSpy("scope");
spy.call(scopeObj, 42, "blue");
// Also can use spy.calls[0].object
expect(spy.mostRecentCall.object).toBe(scopeObj);
});

How to create test doubles with Sinon that prevents execution of the actual function

I am doing javascript unit testing with Mocha and Sinon. I want to test whether under certain circumstances, a certain method is called.
However, so far I couldn't manage only to test if the method was called. To make it clearer, I want a fake method to replace the actual method, because I don't want to simulate my whole application state to make this simple test pass.
This is my actual test code:
it('calls the handleResults method when its model syncs', function () {
var spy = sinon.stub( this.appview, 'handleResults' );
this.appview.model.fetch();
server.requests[0].respond( 200,
{ "Content-Type": "application/json" },
JSON.stringify( [ { id: "casa", text: "Something" } ] )
);
spy.should.have.been.called;
});
The real this.appview.handleResults method is being called, while I would want to call a fake version which does nothing else than checking whether it was called or not.
What am I doing wrong?
The docs are very clear that by using stub, the original function will be replaced by mock and will not be called:
As spies, stubs can be either anonymous, or wrap existing functions.
When wrapping an existing function with a stub, the original function
is not called.
and
var stub = sinon.stub(object, "method");
Replaces object.method with a
stub function. The original function can be restored by calling
object.method.restore(); (or stub.restore();). An exception is thrown
if the property is not already a function, to help avoid typos when
stubbing methods.

Categories