How to Stub Promise Function and Mock Resolved Output
Mocking and Stubbing walk hand in hand. In this blog, we document stubbing functions with promise constructs. The use cases are going to be based on Models. We keep in mind that there is a clear difference between mocking versus stub/spying and using fakes.
In this article we will talk about:
- Stub a promise construct by replacing it with a fake
- Stub a promising construct by using third-party tools
- Mocking database-bound input and output
Even though this blog post was designed to offer complementary materials to those who bought my Testing
nodejs
Applications book, the content can help any software developer to tuneup working environment. You use this link to buy the book.
Show me the code
//Lab Pet
window.fetch('/full/url/').then(function(res){
service.doSyncWorkWith(res);
return res;
}).catch(function(err){
return err;
});
Example:
What can possibly go wrong?
When trying to figure out how to approach stub functions that return a promise, the following points may be a challenge:
- How to deal with the asynchronous nature of the promise.
- Making stubs drop-in replacements of some portion of the code block, and leave intact anything else.
The following sections will explore more on making points stated above work.
Content
- From Johnny Reeves Blog: Stub the services' Async function, then return mocked response
var sinon = require('sinon');
describe('#fetch()', function(){
before(function(){
//one way
fetchStub = sinon.stub(window, 'fetch').returns(bakedPromise(mockedResponse));
//other way
fetchStub = sinon.stub(window, 'fetch', function(options){
return bakedPromise(mockedResponse);
});
//other way
fetchStub = sinon.stub(window, 'fetch').resolves(mockedResponse);
});
after(function(){ fetchStub.restore(); });
it('works', function(){
//use default function like nothing happened
window.fetch('/url');
assert(fetchStub.called, '#fetch() has been called');
//or
assert(window.fetch.called, '#fetch() has been called');
});
it('fails', function(){
//one way
fetchStub = sinon.stub(window, 'fetch', function(options){
return bakedFailurePromise(mockedResponse);
});
//another way using 'sinon-stub-promise's returnsPromise()
//PS: You should install => npm install sinon-stub-promise
fetchStub = sinon.stub(window, 'fetch').returnsPromise().rejects(reasonMessage);
});
});
Example:
bakedPromise()
is any function that takes a Mocked(baked) Response and returns a promise- This approach doesn't tell you if
Service.doJob()
has been expected. For That: - source
- source
Conclusion
In this article, we established the difference between Promise versus regular callbacks and how to stub promise constructs, especially in database operations context, and replacing them with fakes. Testing tends to be more of art, than science, proactive makes perfect. There are additional complimentary materials in the “Testing nodejs
applications” book.
References
- Testing
nodejs
Applications book - Getting started with
nodejs
andmocha
~ SemaphoreCI Community Tutorials - A TDD Approach to Building a Todo API Using
nodejs
andmongodb
~ SemaphoreCI Community Tutorials - Evan Hahn in “How do I Jasmine“ – has pretty good examples that leverages spies along the way.