{"id":486,"date":"2016-02-21T20:29:05","date_gmt":"2016-02-21T19:29:05","guid":{"rendered":"http:\/\/joost.vunderink.net\/blog\/?p=486"},"modified":"2016-02-28T10:31:41","modified_gmt":"2016-02-28T09:31:41","slug":"automated-software-testing-part-3-writing-tests-and-refactoring","status":"publish","type":"post","link":"https:\/\/joost.vunderink.net\/blog\/2016\/02\/21\/automated-software-testing-part-3-writing-tests-and-refactoring\/","title":{"rendered":"Automated software testing part 3: writing tests, and refactoring"},"content":{"rendered":"<p>Previous: <a href=\"http:\/\/joost.vunderink.net\/blog\/2016\/02\/15\/automated-testing-part-2-testing-strategy-or-what-to-test\/\">part 2<\/a>\u00a0&#8211; Next: <a href=\"http:\/\/joost.vunderink.net\/blog\/2016\/02\/28\/automated-software-testing-part-4-combining-similar-tests\/\">part 4<\/a><\/p>\n<p>In this post, we will look at the process of writing unit tests for existing code. In the process, we will be refactoring the code to make the tests easier and clearer &#8211; and to improve the code.<\/p>\n<p>The code\u00a0is in <a href=\"https:\/\/nodejs.org\/en\/\">node.js<\/a> with <a href=\"http:\/\/expressjs.com\/\">the express framework<\/a>. However, the approach we will take is not language specific. Reading this post can help you even if you have never written any node.js code.<\/p>\n<p>This is a long post and would have been better as a screencast. When I have created that screencast, I&#8217;ll add a link to it in this post.<\/p>\n<p>You can also find the code below in the <span class=\"lang:default decode:true crayon-inline\">src\/unit-test-1<\/span>\u00a0\u00a0dir of my <a href=\"https:\/\/github.com\/joostvunderink\/jvblog-node-samples\">blog code repository<\/a>.<\/p>\n<p><em>Note: The code snippets contain a few things that should be done differently in production code. For example, using asynchronous fs calls (e.g. <\/em><span class=\"lang:default decode:true crayon-inline\">fs.readFile<\/span><em>\u00a0 instead of <\/em><span class=\"lang:default decode:true crayon-inline\">fs.readFileSync<\/span><em>\u00a0); using\u00a0<\/em><span class=\"lang:default decode:true crayon-inline\">&#8220;use strict;&#8221;<\/span><em>\u00a0 ; and using modules like <a href=\"https:\/\/github.com\/nomiddlename\/log4js-node\">log4js<\/a>\u00a0and\u00a0<a href=\"http:\/\/sinonjs.org\/\">sinon<\/a>.<\/em><\/p>\n<h2>Step 1<\/h2>\n<p>This is the code we shall write tests for:<\/p>\n<pre class=\"lang:js decode:true \" title=\"Unit test server version 1\">\/\/ server.js\r\n\r\n\/\/ Express is a web framework for node.js.\r\nvar express = require('express');\r\n\r\n\/\/ Moment is a date manipulation library.\r\nvar moment = require('moment');\r\n\r\n\/\/ Fs is a core module of node.js to manipulate the file system.\r\nvar fs = require('fs');\r\n\r\nvar app = express();\r\n\r\n\/\/ When a http request is done on \/count\/start, execute this code.\r\n\/\/ req contains request information, which we are not using.\r\n\/\/ res is the response object.\r\napp.get('\/count\/start', function (req, res) {\r\n  \/\/ Read the server log file\r\n  var data = fs.readFileSync(__dirname + '\/server.log').toString();\r\n\r\n  \/\/ and count how many lines contain the words 'server started'.\r\n  var numStartLines = data\r\n    .split(\/\\r\\n|\\r|\\n\/)\r\n    .filter(function(line) { return \/server started\/.test(line); })\r\n    .length;\r\n\r\n  \/\/ Send a JSON answer that shows how many times the server has been started.\r\n  res.send({ numStart: numStartLines });\r\n});\r\n\r\nvar server = app.listen(64001, function () {\r\n  \/\/ When the server starts, log that it started.\r\n  var msg = moment().format('YYYY-MM-DD HH:mm:ss') + ' - server started\\n';\r\n  fs.appendFileSync(__dirname + '\/server.log', msg);\r\n  \r\n  var host = server.address().address\r\n  var port = server.address().port\r\n\r\n  console.log(\"Unit test 1 app v1 listening at http:\/\/%s:%s\", host, port)\r\n});\r\n<\/pre>\n<p>This code starts an HTTP server that listens on <span class=\"lang:default decode:true crayon-inline \">localhost:64001<\/span>\u00a0. It writes to a log file whenever it is started. On an HTTP request to <span class=\"lang:default decode:true crayon-inline \">http:\/\/localhost:64001\/count\/start<\/span>\u00a0, it returns a JSON structure that shows how many times the server has started. Like this:<\/p>\n<pre class=\"lang:sh decode:true \" title=\"Curling the server\">czapka:~$ curl localhost:64001\/count\/start\r\n{\"numStart\":5}<\/pre>\n<p>We want to test if the correct count is returned by our URL &#8211; so the code that is the second argument of <span class=\"lang:default decode:true crayon-inline \">app.get(&#8216;\/count\/start&#8217;, function)<\/span>\u00a0. How can we do that?<\/p>\n<p>If we load <span class=\"lang:default decode:true crayon-inline \">server.js<\/span>\u00a0 in our test file, the server is actually started and the real log file is being used. This is not an option. Besides, running the server and testing the HTTP call is a\u00a0high level test &#8211; let&#8217;s test it on a lower level. To do this, we need to separate the count start function from the server itself.<\/p>\n<h2>Step 2<\/h2>\n<p>We&#8217;ll create a <span class=\"lang:default decode:true crayon-inline \">count.js<\/span>\u00a0 file to put the count start functionality in. It looks like this:<\/p>\n<pre class=\"lang:js decode:true\" title=\"Step 2 count.js\">\/\/ count.js\r\n\r\nvar fs = require('fs');\r\n\r\nfunction countStart(req, res) {\r\n  var data = fs.readFileSync(__dirname + '\/server.log').toString();\r\n  var numStartLines = data\r\n    .split(\/\\r\\n|\\r|\\n\/)\r\n    .filter(function(line) { return \/server started\/.test(line); })\r\n    .length;\r\n  res.send({ numStart: numStartLines });\r\n}\r\n\r\nmodule.exports = {\r\n  countStart: countStart\r\n};\r\n<\/pre>\n<p>The <span class=\"lang:default decode:true crayon-inline \">app.get()<\/span>\u00a0 line in <span class=\"lang:default decode:true crayon-inline \">server.js<\/span>\u00a0 needs to be changed as well:<\/p>\n<pre class=\"lang:js decode:true\" title=\"Step 2 modifications to server.js\">\/\/ Modifications to server.js\r\n\r\nvar count = require('.\/count');\r\napp.get('\/count\/start', count.countStart);<\/pre>\n<p>Excellent. Now we can create <span class=\"lang:default decode:true crayon-inline \">count.spec.js<\/span>\u00a0 to test the new <span class=\"lang:default decode:true crayon-inline \">countStart<\/span>\u00a0 function. Let&#8217;s give it a shot. We&#8217;ll use <a href=\"https:\/\/mochajs.org\/\">the mocha framework<\/a> for testing and <a href=\"https:\/\/www.npmjs.com\/package\/should\">should<\/a> to check actual results against expected results.<\/p>\n<pre class=\"lang:js decode:true\" title=\"Step 2 count.spec.js first attempt\">\/\/ count.spec.js\r\n\r\nrequire('should');\r\n\r\nvar count = require('.\/count');\r\n\r\ndescribe('countStart', function() {\r\n  it('should count the number of times the server was started', function() {\r\n    var req = ..?\r\n    var res = ..?\r\n    count.countStart(req, res);\r\n    something.should.equal(somethingElse);\r\n  });\r\n});\r\n<\/pre>\n<p>There are a few problems here.<\/p>\n<ul>\n<li>This test will read the real <span class=\"lang:default decode:true crayon-inline \">server.log<\/span>\u00a0 file. Therefore, the number of &#8220;server start&#8221; lines can be different each time you run this test. Additionally, the file may not exist at all.<\/li>\n<li>The <span class=\"lang:default decode:true crayon-inline \">countStart<\/span>\u00a0 function does not return a useful value; instead it call <span class=\"lang:default decode:true crayon-inline \">res.send<\/span>\u00a0 with the value to be tested. That makes it more difficult to test.<\/li>\n<\/ul>\n<p>Let&#8217;s get it to work anyway, by creating a fake <span class=\"lang:default decode:true crayon-inline \">res<\/span>\u00a0 object with a <span class=\"lang:default decode:true crayon-inline \">send<\/span>\u00a0 method.<\/p>\n<pre class=\"lang:js decode:true\" title=\"Step 2 count.spec.js\">\/\/ count.spec.js\r\n\r\ndescribe('countStart', function() {\r\n  it('should count the number of times the server was started', function() {\r\n    var dataSent;\r\n    \r\n    var fakeResObject = {\r\n      send: function(data) {\r\n        dataSent = data;\r\n      }\r\n    };\r\n\r\n    count.countStart({}, fakeResObject);\r\n\r\n    \/\/ We know that dataSent should be an object with the key\r\n    \/\/ \"numStart\". However, we don't know the value.\r\n    dataSent.should.have.keys(['numStart']);\r\n    dataSent.numStart.should.be.a.number;\r\n  });\r\n});\r\n<\/pre>\n<p>Now we have something that works, most of the time. In my opinion, this is not acceptable test code yet. So let&#8217;s fix the first problem, that the test code uses the same <span class=\"lang:default decode:true crayon-inline \">server.log<\/span>\u00a0 file as the server itself.<\/p>\n<h2>Step 3<\/h2>\n<p>The problem with the current approach, is that the <span class=\"lang:default decode:true crayon-inline \">countStart<\/span>\u00a0 function determines the log file by itself. It would be better if the log file was determined elsewhere, and then given to (or asked by) the countStart function. Ever since I saw <a href=\"http:\/\/misko.hevery.com\/2008\/11\/11\/clean-code-talks-dependency-injection\/\">Mi\u0161ko Hevery&#8217;s\u00a0talk on Dependency Injection<\/a>, I&#8217;ve been a fan of DI; and even\u00a0if\u00a0this is\u00a0not be exactly DI, it&#8217;s certainly very similar.<\/p>\n<p>We&#8217;ll move the log file related code to a separate file, <span class=\"lang:default decode:true crayon-inline \">log.js<\/span>\u00a0and we&#8217;ll make it possible to set and get the filename of the log file.<\/p>\n<pre class=\"lang:js decode:true\" title=\"Step 2 log.js\">\/\/ log.js\r\n\r\nvar fs = require('fs');\r\nvar moment = require('moment');\r\n\r\nvar logFileName;\r\n\r\nfunction getFile() {\r\n  return logFileName;\r\n}\r\n\r\nfunction setFile(filename) {\r\n  logFileName = filename;\r\n}\r\n\r\nfunction logMessage(message) {\r\n  fs.appendFileSync(getFile(), moment().format('YYYY-MM-DD HH:mm:ss') + ' - ' + message + '\\n');\r\n}\r\n\r\nmodule.exports = {\r\n  getFile   : getFile,\r\n  setFile   : setFile,\r\n  logMessage: logMessage,\r\n};\r\n<\/pre>\n<p>Additionally, we&#8217;ll need a few changes to server.js and count.js.<\/p>\n<pre class=\"lang:js decode:true\" title=\"Step 3 modification to server.js\">\/\/ server.js changes\r\n\r\nvar log     = require('.\/log');\r\nlog.setFile(__dirname + '\/server.log');\r\n\r\nvar server = app.listen(64001, function () {\r\n  log.logMessage('server started');\r\n  \r\n  \/\/ The old code here\r\n});\r\n<\/pre>\n<pre class=\"lang:js decode:true \" title=\"Step 3 count.js changes\">\/\/ count.js\r\n\r\nvar log = require('.\/log');\r\n\r\nfunction countStart(req, res) {\r\n  var filename = log.getFile();\r\n  var data = fs.readFileSync(filename).toString();\r\n  \/\/ Rest is unchanged.\r\n}\r\n<\/pre>\n<p>We&#8217;re getting somewhere.<\/p>\n<p>In our test file, we can now use a different log file. We&#8217;ll have to create this file as part of the setup of our test, and remove it at the end. Here&#8217;s our modified <span class=\"lang:default decode:true crayon-inline \">count.spec.js<\/span>\u00a0:<\/p>\n<pre class=\"lang:js decode:true \" title=\"Step 3 count.spec.js\">\/\/ count.spec.js\r\n\r\nrequire('should');\r\n\r\nvar fs    = require('fs');\r\nvar count = require('.\/count');\r\nvar log   = require('.\/log');\r\n\r\ndescribe('countStart', function() {\r\n  var logFileName = __dirname + '\/unit-test-file.log';\r\n\r\n  function cleanupTestFile() {\r\n    if (fs.existsSync(logFileName)) {\r\n      fs.unlinkSync(logFileName);\r\n    }\r\n  }\r\n  \/\/ This code is run before each test.\r\n  beforeEach(cleanupTestFile);\r\n  \/\/ And this code after each test.\r\n  afterEach(cleanupTestFile);\r\n\r\n  it('should count the number of times the server was started', function() {\r\n    var dataSent;\r\n    \r\n    var fakeResObject = {\r\n      send: function(data) {\r\n        dataSent = data;\r\n      }\r\n    };\r\n\r\n    fs.appendFileSync(logFileName, '2016-02-20 14:53:09 - server started\\n');\r\n    fs.appendFileSync(logFileName, '2016-02-20 14:55:50 - server started\\n');\r\n\r\n    log.setFile(logFileName);\r\n\r\n    count.countStart({}, fakeResObject);\r\n    dataSent.should.eql({ numStart: 2 });\r\n  });\r\n});\r\n<\/pre>\n<p>Note that we can now actually test whether the number of lines is 2, because we control the log file in the test. In step 2, we could not predict how many lines there would be. That means that this test tests our function better. In step 2, the <span class=\"lang:default decode:true crayon-inline \">countStart<\/span>\u00a0 function could just as easily always have returned 42, and our test would not have noticed that.<\/p>\n<p>Regarding our DI approach:\u00a0we&#8217;re not injecting the log file name into the <span class=\"lang:default decode:true crayon-inline \">countStart<\/span>\u00a0 function yet, because this function is being called by the express framework. Let&#8217;s work on that now. This should also fix the second problem mentioned at the end of step 2.<\/p>\n<h2>Step 4<\/h2>\n<p>If we look at the <span class=\"lang:default decode:true crayon-inline \">countStart<\/span>\u00a0 function, we see that it is currently doing 2 things: it is handling the HTTP request and sending a response, and it&#8217;s counting the &#8220;server started&#8221; lines in the log file. In general, when a function does 2 things that are easily separated, it&#8217;s good to separate the two. This makes the code cleaner, easier to reuse, and easier to test.<\/p>\n<p>Here&#8217;s the new count.js:<\/p>\n<pre class=\"lang:js decode:true\" title=\"Step 4 count.js\">\/\/ count.js\r\n\r\nvar fs  = require('fs');\r\nvar log = require('.\/log');\r\n\r\nfunction countStart(req, res) {\r\n  var numStartLines = _countStart(log.getFile());\r\n  res.send({ numStart: numStartLines });\r\n}\r\n\r\nfunction _countStart(filename) {\r\n  var data = fs.readFileSync(filename).toString();\r\n  var numStartLines = data\r\n    .split(\/\\r\\n|\\r|\\n\/)\r\n    .filter(function(line) { return \/server started\/.test(line); })\r\n    .length;\r\n  return numStartLines;\r\n}\r\n\r\nmodule.exports = {\r\n  countStart: countStart\r\n};\r\n<\/pre>\n<p>The function <span class=\"lang:default decode:true crayon-inline \">countStart<\/span>\u00a0 now only gets the number of &#8220;server start&#8221; lines from elsewhere, and returns a data structure. The <span class=\"lang:default decode:true crayon-inline \">_countStart<\/span>\u00a0 function (ok, the name could have been better) no longer has any knowledge about HTTP requests or responses, and just counts lines in a file.<\/p>\n<p>This also means that we should test both functions. Both tests will be easier than the single test of step 3.<\/p>\n<p>First, we&#8217;ll test <span class=\"lang:default decode:true crayon-inline \">_countStart<\/span>\u00a0. Currently, this function is not listed in the exports of <span class=\"lang:default decode:true crayon-inline \">count.js<\/span>\u00a0, because it&#8217;s a private function (maybe it should be, especially if we want to use this functionality in other parts of the cade). There is a trick to get access to this function in our test suite, and that trick is <a href=\"https:\/\/github.com\/jhnns\/rewire\">the rewire module<\/a>.<\/p>\n<p>This is how we test <span class=\"lang:default decode:true crayon-inline \">_countStart<\/span>\u00a0.<\/p>\n<pre class=\"lang:js decode:true\" title=\"Step 4 count.spec.js countStart part\">\/\/ count.spec.js first part\r\n\r\n  describe('_countStart', function() {\r\n    var logFileName = __dirname + '\/unit-test-file.log';\r\n    function cleanupTestFile() {\r\n      if (fs.existsSync(logFileName)) {\r\n        fs.unlinkSync(logFileName);\r\n      }\r\n    }\r\n    beforeEach(cleanupTestFile);\r\n    afterEach(cleanupTestFile);\r\n\r\n    it('should count the number of times the server was started', function() {\r\n      var dataSent;\r\n      \r\n      fs.appendFileSync(logFileName, '2016-02-20 14:53:09 - server started\\n');\r\n      fs.appendFileSync(logFileName, '2016-02-20 14:55:50 - server started\\n');\r\n\r\n      \/\/ Get the private _countStart function. We use rewire, because the\r\n      \/\/ function is not in module.exports so we can't access it directly.\r\n      var _countStart = count.__get__('_countStart');\r\n\r\n      var numStart = _countStart(logFileName);\r\n      numStart.should.equal(2);\r\n    });\r\n  });\r\n<\/pre>\n<p>This looks very similar to the test in step 3. The difference is, that we don&#8217;t fiddle around with a fake response object anymore: <span class=\"lang:default decode:true crayon-inline \">_countStart<\/span>\u00a0 simply returns the count.<\/p>\n<p>The other test is of countStart. In this test, we use a very important principle: <strong>we don&#8217;t need to test what has already been tested elsewhere<\/strong>. Therefore, we are going to replace the <span class=\"lang:default decode:true crayon-inline \">_countStart<\/span>\u00a0 function be a function of our own. This is called <a href=\"https:\/\/davidwalsh.name\/monkey-patching\">monkey patching<\/a>.<\/p>\n<pre class=\"lang:js decode:true\" title=\"Step 4 count.spec.js second part\">\/\/ count.spec.js second part\r\n\r\n  describe('countStart', function() {\r\n    it('should respond with the number of times the server was started', function() {\r\n      var dataSent;\r\n      var fakeResObject = {\r\n        send: function(data) {\r\n          dataSent = data;\r\n        }\r\n      };\r\n\r\n      var logFileName = 'testfile.log';\r\n      log.setFile(logFileName);\r\n\r\n      var logFileArgument;\r\n\r\n      \/\/ We overwrite the private _countStart function so it returns what we\r\n      \/\/ want. After all, we are testing the countStart function here; the\r\n      \/\/ _countStart function has already been tested above.\r\n      \/\/ Also, we want to verify that countStart calls _countStart with the correct\r\n      \/\/ filename argument. \r\n      \/\/ The __set__() call returns a function that, when called, resets the\r\n      \/\/ overwritten function back to its original.\r\n      var reset = count.__set__('_countStart', function(filename) {\r\n        logFileArgument = filename;\r\n        return 2;\r\n      });\r\n\r\n      count.countStart({}, fakeResObject);\r\n\r\n      dataSent.should.eql({ numStart: 2 });\r\n      logFileArgument.should.equal(logFileName);\r\n\r\n      reset();\r\n    });\r\n  });\r\n<\/pre>\n<p>That&#8217;s a lot of preparation for a single test! This actually happens often, that the preparation for a unit test is significantly more code than the call and verification. It&#8217;s just part of testing.<\/p>\n<p>In the above\u00a0test, we still need the fake response object, but we don&#8217;t need to write files anymore.<\/p>\n<p>This is a reasonable final state for our code. There is one more refactoring improvement that can be done.<\/p>\n<h2>Step 5<\/h2>\n<p>The last thing that bothers me is the <span class=\"lang:default decode:true crayon-inline \">_countStart<\/span>\u00a0 function. This function does too much: it reads stuff from a file, and it counts stuff. Especially the counting part is a reasonably complex operation, and we&#8217;d like to test that separately.<\/p>\n<p>Let&#8217;s split it into two parts.<\/p>\n<pre class=\"lang:js decode:true\" title=\"Step 5 count.js modification to _countStart\">\/\/ count.spec.js modifications\r\n\r\nfunction _countStart(filename) {\r\n  var data = _readFile(filename);\r\n  return _countMatchingLinesInString(data, \/server started\/);\r\n}\r\n\r\nfunction _readFile(filename) {\r\n  return fs.readFileSync(filename).toString();\r\n}\r\n\r\nfunction _countMatchingLinesInString(string, regexp) {\r\n  return string.split(\/\\r\\n|\\r|\\n\/)\r\n    .filter(function(line) { return regexp.test(line); })\r\n    .length;\r\n}\r\n<\/pre>\n<p>There. Now it&#8217;s much easier to test the matching function.<\/p>\n<pre class=\"lang:js decode:true\" title=\"Step 5 count.spec.js testing matching function\">\/\/ conut.spec.js part\r\n\r\n  describe('_countMatchingLinesInString', function() {\r\n    it('should count the number of lines that match in a string', function() {\r\n      var _countMatchingLinesInString = count.__get__('_countMatchingLinesInString');\r\n\r\n      var string = 'blah server started blah\\n' +\r\n                   'this line should not match\\n' +\r\n                   'server started server started should count as one\\n';\r\n      var regexp = \/server started\/;\r\n      var num = _countMatchingLinesInString(string, regexp);\r\n      num.should.equal(2);\r\n    });\r\n  });\r\n<\/pre>\n<p>The test for <span class=\"lang:default decode:true crayon-inline \">_readFile<\/span>\u00a0 is also simple.<\/p>\n<pre class=\"lang:js decode:true\" title=\"Step 5 count.spec.js testing _readFile\">\/\/ conut.spec.js part\r\n\r\n  describe('_readFile', function() {\r\n    var logFileName = __dirname + '\/unit-test-file.log';\r\n    function cleanupTestFile() {\r\n      if (fs.existsSync(logFileName)) {\r\n        fs.unlinkSync(logFileName);\r\n      }\r\n    }\r\n    beforeEach(cleanupTestFile);\r\n    afterEach(cleanupTestFile);\r\n\r\n    it('should read the log file', function() {\r\n      var _readFile = count.__get__('_readFile');\r\n\r\n      fs.appendFileSync(logFileName, 'line one\\n');\r\n      fs.appendFileSync(logFileName, 'line two\\n');\r\n\r\n      var data = _readFile(logFileName);\r\n      data.should.equal('line one\\nline two\\n');\r\n    });\r\n  });\r\n<\/pre>\n<p>Looking at these four functions, we can notice a difference between the two pairs.\u00a0\u00a0<span class=\"lang:default decode:true crayon-inline \">_readFile<\/span>\u00a0 and <span class=\"lang:default decode:true crayon-inline \">_countMatchingLinesInString<\/span>\u00a0 are functions that do actual work. Let&#8217;s call them\u00a0<strong>worker functions<\/strong>. The functions countStart and _countStart don&#8217;t do any work, but they link worker functions together. Let&#8217;s call these\u00a0<strong>linker functions<\/strong>.<\/p>\n<p>To test a linker\u00a0function, all you need to do is to verify that it calls the right worker functions in the right order, with the right arguments. This can be done by mocking the worker functions; there is no need to call the actual worker functions. For example, for <span class=\"lang:default decode:true crayon-inline \">_countStart<\/span>\u00a0:<\/p>\n<pre class=\"lang:js decode:true\" title=\"Step 5 count.spec.js testing _countStart\">\/\/ conut.spec.js part\r\n\r\n  describe('_countStart', function() {\r\n    it('should call _readFile and _countMatchingLinesInString', function() {\r\n      var _readFileArg, _countArg1, _countArg2;\r\n      var fileContents = '123 server started\\n456 server started server started\\nthird line';\r\n      var reset1 = count.__set__('_readFile', function(arg) {\r\n        _readFileArg = arg;\r\n        return fileContents;\r\n      });\r\n      var reset2 = count.__set__('_countMatchingLinesInString', function(arg1, arg2) {\r\n        _countArg1 = arg1;\r\n        _countArg2 = arg2;\r\n      });\r\n\r\n      var filename = 'testfile.log';\r\n\r\n      var _countStart = count.__get__('_countStart');\r\n      _countStart(filename);\r\n\r\n      _readFileArg.should.eql(filename);\r\n      _countArg1.should.eql(fileContents);\r\n      _countArg2.should.eql(\/server started\/);\r\n      reset1();\r\n      reset2();\r\n    });\r\n  });\r\n<\/pre>\n<p>For this specific example, I&#8217;m not sure whether step 5 is overkill. It might be. I found it important to show you though, because for more complex situations, the separation into worker functions and linker\u00a0functions can make your life much easier.<\/p>\n<h2>Conclusions<\/h2>\n<p>Even for a very simple server that only does one thing, writing unit tests will make you think about and improve the design of your code. If a function or module is hard to test, it is often an indication of a problem with the design.<\/p>\n<p>When testing, keep in mind dependency injection and the difference between worker functions and linker functions. Also think about which parts of the code have already been tested elsewhere, so you know when it&#8217;s safe to mock or monkey patch that code. This will help you to restructure your code to make it easier to test &#8211; and hopefully also easier to reuse and maintain.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Previous: part 2\u00a0&#8211; Next: part 4 In this post, we will look at the process of writing unit tests for existing code. In the process, we will be refactoring the code to make the tests easier and clearer &#8211; and &hellip; <a href=\"https:\/\/joost.vunderink.net\/blog\/2016\/02\/21\/automated-software-testing-part-3-writing-tests-and-refactoring\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10,272],"tags":[],"class_list":["post-486","post","type-post","status-publish","format-standard","hentry","category-software-development","category-testing-software-development"],"_links":{"self":[{"href":"https:\/\/joost.vunderink.net\/blog\/wp-json\/wp\/v2\/posts\/486"}],"collection":[{"href":"https:\/\/joost.vunderink.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/joost.vunderink.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/joost.vunderink.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/joost.vunderink.net\/blog\/wp-json\/wp\/v2\/comments?post=486"}],"version-history":[{"count":9,"href":"https:\/\/joost.vunderink.net\/blog\/wp-json\/wp\/v2\/posts\/486\/revisions"}],"predecessor-version":[{"id":507,"href":"https:\/\/joost.vunderink.net\/blog\/wp-json\/wp\/v2\/posts\/486\/revisions\/507"}],"wp:attachment":[{"href":"https:\/\/joost.vunderink.net\/blog\/wp-json\/wp\/v2\/media?parent=486"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/joost.vunderink.net\/blog\/wp-json\/wp\/v2\/categories?post=486"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/joost.vunderink.net\/blog\/wp-json\/wp\/v2\/tags?post=486"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}