How to Mock HTTP Request and Response
The depth of an HTTP request or response mock brings a level of complexity to the whole system. In this article, we revisit some techniques used to mock HTTP request/response when used in the same test case.
In this article we will talk about:
- Mocking Request Objects
- Mocking Response Objects
- Mocking Request and Response object in the same test case.
- When does it make sense to mock both Request and Response.
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
module.exports.getUsers = function getUsers(req, res, next){
UserModel.find(req.params, (error, users){
if(error) return next(error, null);
return res.status(200).json(users);
});
}
Example: in controller/get-users.js
What can possibly go wrong?
When trying to figure out how to approach mocking request and response objects, the following points may be a challenge:
- Stubbing the right request/response methods
- Mock output that can be consumed by the other callers
- Stubbing request/response handlers in the same test case
- Strategic mocking that can make a live server obsolete
How to mock Request/Response Objects the easy way
Testing an expressjs
middleware provides a good use case where mocking a request and response in the same test case makes sense.
Key objectives are:
- Spying if certain calls have been called
- Make sure the requests don't leave the local machine.
var sinon = require('sinon'),
chai = require('chai'),
expect = chai.expect,
getUsers = require('./controller').getUsers;
describe("getUsers()", function() {
it("should guarantee a response", function() {
var req = {},
res = { send: sinon.spy()},
next = sinon.spy();
getUsers(req, res, next);
expect(res.send.calledOnce).to.equal(true);
res.send.restore();
});
});
code excerpt adapted from – Unit Testing Controllers the Easy Way in Express 4
Particular Case: How to mock a response that uses a streaming, or other hard to mock interfaces. Keyword: let the flow intact, but fake read/write data instead.
Mocking request
Request object provided by node-mocks-http
is pretty similar to the request provided by the native http
found in nodejs
library
var request;
//When method = GET|DELETE
request = httpMock.createRequest({method: method, url: url});
//When method = PUT|POST
var request = httpMock.createRequest({method, url, body: body})
Mocking Response
//initialization(or beforeEach)
var response = httpMock.createResponse({
eventEmitter: require('events').EventEmitter
});
//Usage: somewhere in tests
let next = sinon.spy();
getUsers(request, response, next);
response.on('end|data|error', function(error){
//write tests in this close.
});
Using node-mocks-http
is in the gray area of integration testing. However, this technique can be verifiable in use cases where the first strategy falls short.
There is more on integration testing mocking strategy: How to Mock HTTP Request and Response ~ Integration testing use case
Conclusion
In this article, we revisited strategies to mock HTTP Request and Response methods in the same test case, while using mock data to emulate interaction with remote systems. We also re-iterated the difference between stubbing and mocking, and how spies(fake) fall into the testing big picture. There are additional complimentary materials in the “Testing nodejs
applications” book on this very same subject.
References
- Testing
nodejs
Applications book - Stubbing HTTP Requests
- Getting started with
nodejs
andmocha
~ SemaphoreCI Community Tutorials - A TDD Approach to Building a Todo API Using
nodejs
andmongodb
~ SemaphoreCI Community Tutorials expressjs
Request/Response mocking utility ~ mock-express-request- HTTP Response assertions utility ~ chai-http