In a previous post I show how you can you create a node.js web server without any middleware or additional dependencies. One of the downsides of that approach is that it makes the http server setup more difficult to maintain and read. In today's post I will show how to refactor the code to be more readable and how to setup your unit tests. In keeping with the spirit of the original requirements I didn't add any production dependencies, but I did add nodemon and Jasmine as dev dependencies. You don't need nodemon, but it does make development much easier. So you could create a full production node.js web server with full unit test coverage and only add a single dependency (and its child dependencies) other than node/npm itself. Let's get started.
The first thing I did was break out the http server setup into its own class. If you compare the server as it is now to the original post you'll notice a couple of things right away. First I created the server as a class and required a router to be supplied in the constructor. The second thing is that I pull the path logic out of the server. As a result of removing a lot of the logic the if/else if/else block in the web server is a lot cleaner and easier to read. The main reason I setup the server to accept a router in the constructor was so that I can mock the router in my unit tests. The rest of the code is very simple and straightforward.
As a result of pulling the http server into its own class my app.js file is now very small. As you can see, all I'm doing is getting the required dependencies, newing up the server instance and starting the server. Next let's take a look at the router class.
What I did for the router class was pull the logic that used to be in the server's if/else if/else blocks and moved that logic into its own method. The benefit of this is increased readability and test ability. Now with the server class setup and the logic added to the router class it's time to start unit testing.
I do not recommend trying to write your own unit testing library or framework so this is the one external dependency that I added to this project. I have the most experience with Jasmine so that's what I used here. I did not add a test runner like Karma or Mocha instead I just used npm and nodemon to setup a watch in my package.json that I can use for TDD.
I started with unit testing the router itself. If you've used Jasmine before then everything should be pretty familiar. I'm creating spy objects for the http response, task controller, and user controller to make sure that the method I expect to be called are in fact being called. I created a simple request class in this file to mock the http request that would be incoming request. You don't have to do this, but it was the easiest option for this simple server. Testing the http server itself proved to be more difficult.
The requirement that I be able to supply a mocked router to the http server was a main reason why I refactored the server. In the end I'm very happy with the results and glad I went with the approach I did. Since I'm testing the actual http server I needed to start it so I could send requests to it. Something else that kept tripping me up was that I needed to place the expect in the callback of the http request. At first I would fire off the http request and then on the next line place the expect statement. The expect would trigger before the request finished and would fail the test. Debugging these server tests was the hardest part of this project. Once I figured out that I had to put the expect in the request callback everything came together nicely.
There you have it. A very simply node.js web server that doesn't use any middleware or external dependencies (other than for unit testing) and is fully capable of being unit tested. You can see the completed project at my github. Maybe at some point in the future I'll setup an Azure Devops project for this and automate deployment as a function, but that will be a project for another day. Hope you enjoyed this post and let me know what you think. And as always,
​Happy Coding. Sean Wernimont The Blind Squirrel Copyright 2015-2020
|
AuthorWelcome to The Blind Squirrel (because even a blind squirrel occasionally finds a nut). I'm a full-stack web and mobile developer that writes about tips and tricks that I've learned in Swift, C#, Azure, F# and more. Archives
April 2018
Categories
All
|