After much hair pulling and numerous searches I’ve settled on using Mocha as the test framework. Since I had downloaded WebStorm I thought I’d use the inbuilt JsTestDriver framework – but looks like I can’t test the request/response cycle with it (or maybe I can; Mocha is just a whole lot easier..)
The structure of the test
In order to test the code described in the previous article, I had to refactor the original production code – I’ll show that later. Let me first walk you through the process of setting up the test.
At its base, the test needs to do the following:
- Send the request
- Verify the response.
Since I am setting the response status as well as the response data, we can further break up the ‘Verify response’ part into verifying the response status and verifying the response data. The test now looks like this:
- Send the request
- Verify the response status.
- Verify the response data.
However, in order to send the request and receive a response, the server needs to be up and running. Which means that the test now needs to do the following
- Start the server
- Send the request
- Verify the response status.
- Verify the response data.
Since the test is setting up the server, the test should also tear it down. With that in mind, the test will finally look like this:
- Start the server
- Send the request
- Verify the response status.
- Verify the response data.
- Tear down the server.
Restructuring the Hello World code
The Hello World code looked like this. In this case the server started automatically.
var http = require(“http”); |
http.createServer(function(request, response) { |
response.writeHead(200, {“Content-Type”: “text/plain”}); |
response.write(“Hello World”); |
response.end(); |
}).listen(8888); |
Now, since the test needs to start/stop the server, we will refactor the code to look like this.
var http = require(“http”); |
var server = http.createServer(function (req, res) { |
console.log(‘Received request’); |
res.writeHead(200, { ‘Content-Type’: ‘text/plain’ }); |
res.write(‘Hello World!\n’); |
res.end() |
}); |
var listen = function (port) { |
server.listen(port, function() { |
console.log(‘Listening on port: ‘ + port); |
}); |
}; |
var close = function () { |
server.close(function(){ |
console.log(‘Closing connection!’); |
}); |
}; |
module.exports.listen = listen; |
module.exports.close = close; |
Observe the last 2 lines. In order for the test to access the listen and close functions we need to export them. Here’s a great post on how exports work.
Setting up the test code
With the Hello World code out of the way, let us now move onto the test code. In the beginning I mentioned that I’d be using Mocha as the test framework. For those of you’ll who’ve been following the previous post and have decided to use WebStorm, here’s how you can hook up Mocha in WebStorm – it’s real easy. Once you go through the video you’ll also figure out how to get rid of all those ugly squiggles that show up in the IDE . Those squiggles are WebStorm’s way of letting you know that there is something amiss. When you take care of them, you should see a green rectangle in the upper right-hand corner of the IDE indicating that WebStorm is happy!
Side note on how to fix all the WebStorm inspection issues
As you’d have already seen in the video, most of the issues in the code are because you have not included the required JavaScript libraries. For the purposes of this demo, you need to include the following libraries. Refer to this documentation to find out how to configure JavaScript libraries in WebStorm.
Mocha – Test framework
Should – For all the describe/it functions (in the demo we are only using the it function)
Node.js Core Modules – Includes all the core modules such as http
Node – Now this one is kind of strange. I had to include it in order to remove the inspection warnings from my assert statements. I would imagine that assert would have been a part of should or the Node Core modules – note to self: investigate this.
With the Mocha set up complete, here’s what the test code will look like
var server = require(‘../src/server.js’); |
var http = require(‘http’); |
var assert = require(‘assert’); |
before(function () { |
server.listen(8888); |
}); |
after(function () { |
server.close(); |
}); |
it(‘should return 200’, function (done) { |
http.get(‘http://localhost:8888’, function (res) { |
assert.equal(res.statusCode, ‘200’); |
done(); |
}); |
}); |
it(‘should say Hello World\n’, function (done) { |
http.get(‘http://localhost:8888’, function (res) { |
var data = ”; |
res.on(‘data’, function (chunk) { |
data += chunk; |
}); |
res.on(‘end’, function () { |
assert.equal(data, “Hello World!\n”); |
done(); |
}); |
}); |
}); |
Walking through the test code
var server = require(‘../src/server.js’); |
var http = require(‘http’); |
var assert = require(‘assert’); |
We start by importing the various modules. The server variable is used to import the module that we created in the Hello World code. The assert variable is used to import the assert module and is used for assertions in our test cases.
before(function () { |
server.listen(8888); |
}); |
after(function () { |
server.close(); |
}); |
The before and after functions are hooks provided by the Mocha framework. We are instructing Mocha to start the server before the execution of any test and stop the server once all the test cases have been executed.
Since we exported listen and close we are able to access them in these functions!
it(‘should return 200’, function (done) { |
http.get(‘http://localhost:8888’, function (res) { |
assert.equal(res.statusCode, ‘200’); |
done(); |
}); |
}); |
It is Mocha’s implementation of a test case. Here we describe what the test case should be doing; this is pretty neat because once you run the test in the IDE the description shows up in the test results window which makes it easy to read – contrasting this to .Net where I had to give the test functions descriptive names.
The test itself is straight-forward. It makes a get request on the same port that the server is listening. Since the Hello World code returns a 200 status code, the test checks for that. The only interesting thing to note here is the done(). Per the Mocha documentation
“…Testing asynchronous code with Mocha could not be simpler! Simply invoke the callback when your test is complete. By adding a callback (usually named
done
) toit()
Mocha will know that it should wait for completion…”
Since the get function is asynchronous putting the done() in there instructs Mocha to wait for completion. if you didn’t put the done(), the test would complete without ever receiving the request.
it(‘should say Hello World\n’, function (done) { |
http.get(‘http://localhost:8888’, function (res) { |
var data = ”; |
res.on(‘data’, function (chunk) { |
data += chunk; |
}); |
res.on(‘end’, function () { |
assert.equal(data, “Hello World!\n”); |
done(); |
}); |
}); |
}); |
In order to validate the response data, the test code handles the data and the end event on the response object. It is interesting to note that the response is chunked. Once again, we add done() to instruct Mocha that it should wait for completion.
Now if you run the test cases, you should see both of them pass.
The code is available here. Till next time….