{"id":513,"date":"2016-03-14T22:26:11","date_gmt":"2016-03-14T21:26:11","guid":{"rendered":"http:\/\/joost.vunderink.net\/blog\/?p=513"},"modified":"2016-03-14T22:27:13","modified_gmt":"2016-03-14T21:27:13","slug":"automated-software-testing-part-6-stubbing","status":"publish","type":"post","link":"https:\/\/joost.vunderink.net\/blog\/2016\/03\/14\/automated-software-testing-part-6-stubbing\/","title":{"rendered":"Automated software testing part 6: stubbing"},"content":{"rendered":"<p>Previous: <a href=\"http:\/\/joost.vunderink.net\/blog\/2016\/03\/06\/automated-software-testing-part-5-spying\/\">part 5<\/a><\/p>\n<p>You can also find the code below in the <span class=\"lang:default decode:true  crayon-inline \">src\/unit-test-4<\/span>\u00a0\u00a0 dir of my <a href=\"https:\/\/github.com\/joostvunderink\/jvblog-node-samples\">blog code repository<\/a>.<\/p>\n<p>In the previous post, we talked about spying. With a test spy, you can spy on method calls and see how they are called. This is a bit like listening in on a conversation passively.<\/p>\n<p>The next step is to provide an answer to a method call, similar to interrupting someone who is about to answer a question, and giving your own &#8211; different &#8211; answer.<\/p>\n<p>This is done via a <a href=\"http:\/\/sinonjs.org\/docs\/#stubs\">test stub<\/a>. Let&#8217;s look at an example. You have a website with users, and you want to show the current weather for the logged in user. To do that, you have created a simple function:<\/p>\n<pre class=\"lang:js decode:true \" title=\"generateWeatherReport\">function generateWeatherReport(user) {\r\n  var city = user.location.city;\r\n  var countryCode = user.location.countryCode;\r\n  return weatherService.fetchLocalWeather(city, countryCode)\r\n  .then(function(weatherData) {\r\n    return sprintf('The weather in %s, %s is %s.',\r\n      city, countryCode, weatherData.summary);\r\n  });\r\n}\r\n<\/pre>\n<p>In goes a user, out comes the one-line weather report. Your helper function <span class=\"lang:default decode:true crayon-inline \">fetchLocalWeather<\/span>\u00a0 of the <span class=\"lang:default decode:true crayon-inline \">weatherService<\/span>\u00a0 calls a weather website&#8217;s API to fetch the local weather.<\/p>\n<p>How can we test this?<\/p>\n<pre class=\"lang:default decode:true \" title=\"weather.spec.js first try\">require('should');\r\n\r\nvar weather = require('.\/weather');\r\n\r\ndescribe('generateWeatherReport', function() {\r\n  it('should generate a weather report', function(done) {\r\n    var user = {\r\n      location: {\r\n        city: 'Amsterdam',\r\n        countryCode: 'NL'\r\n      }\r\n    };\r\n\r\n    weather.generateWeatherReport(user)\r\n    .then(function(report) {\r\n      report.should.equal('The weather in Amsterdam, NL is rainy, cold and miserable..');\r\n      done();\r\n    })\r\n    .catch(function(err) {\r\n      done(err);\r\n    });\r\n  });\r\n});\r\n<\/pre>\n<p>This code runs. However, the test only succeeds\u00a0when it is actually rainy, cold and miserable in Amsterdam. Admittedly, this is a large part of the year, but it would be better if this test also succeeds when\u00a0it&#8217;s sunny in Amsterdam.<\/p>\n<p>Again, the sinon module comes to the rescue. With it, we can stub the <span class=\"lang:default decode:true crayon-inline \">fetchLocalWeather<\/span>\u00a0 call, and make it return what we want for a given input. Like this:<\/p>\n<pre class=\"lang:default decode:true \" title=\"weather.spec.js second try\">require('should');\r\nvar sinon = require('sinon');\r\nvar Q = require('q');\r\n\r\nvar weather = require('.\/weather');\r\nvar weatherService = require('.\/weather.service');\r\n\r\ndescribe('generateWeatherReport', function() {\r\n  it('should generate a weather report', function(done) {\r\n    var user = {\r\n      location: {\r\n        city: 'Amsterdam',\r\n        countryCode: 'NL'\r\n      }\r\n    };\r\n\r\n    var fetchLocalWeatherStub = sinon.stub(weatherService, 'fetchLocalWeather');\r\n    fetchLocalWeatherStub.withArgs('Amsterdam', 'NL')\r\n                         .returns(Q.resolve({ summary: 'sunny and great' }));\r\n\r\n    weather.generateWeatherReport(user)\r\n    .then(function(report) {\r\n      report.should.equal('The weather in Amsterdam, NL is sunny and great.');\r\n      done();\r\n    })\r\n    .catch(function(err) {\r\n      done(err);\r\n    })\r\n    .done(function() {\r\n      fetchLocalWeatherStub.restore();\r\n    });\r\n  });\r\n});\r\n<\/pre>\n<p>It&#8217;s necessary to import the <span class=\"lang:default decode:true crayon-inline \">weatherService<\/span>\u00a0 in the test file, even though we are not using it directly. Because imported modules in node.js are only imported once, and then behave like a singleton, the weatherService in the spec file is the same as in the <span class=\"lang:default decode:true crayon-inline \">weather.js<\/span>\u00a0 file.<\/p>\n<p>Using sinon, we overwrite the <span class=\"lang:default decode:true crayon-inline \">fetchLocalWeather<\/span>\u00a0 function. If it&#8217;s called with arguments <span class=\"lang:default decode:true crayon-inline \">Amsterdam, NL<\/span>\u00a0, we return a fixed value.<\/p>\n<p>Note that it&#8217;s important to restore this stub when you&#8217;re done with this test, otherwise <span class=\"lang:default decode:true crayon-inline \">fetchLocalWeather<\/span>\u00a0 for <span class=\"lang:default decode:true crayon-inline \">Amsterdam, NL<\/span>\u00a0 will keep returning this value for other tests in your test suite.<\/p>\n<p>Now if only we could improve\u00a0the actual weather in Amsterdam with sinon!<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Previous: part 5 You can also find the code below in the src\/unit-test-4\u00a0\u00a0 dir of my blog code repository. In the previous post, we talked about spying. With a test spy, you can spy on method calls and see how &hellip; <a href=\"https:\/\/joost.vunderink.net\/blog\/2016\/03\/14\/automated-software-testing-part-6-stubbing\/\">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":[288,188,226,231,233,287,273,275,286],"class_list":["post-513","post","type-post","status-publish","format-standard","hentry","category-software-development","category-testing-software-development","tag-amsterdam","tag-javascript-2","tag-node-js","tag-sinon","tag-stub","tag-stubbing","tag-testing","tag-unit-testing","tag-weather"],"_links":{"self":[{"href":"https:\/\/joost.vunderink.net\/blog\/wp-json\/wp\/v2\/posts\/513"}],"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=513"}],"version-history":[{"count":2,"href":"https:\/\/joost.vunderink.net\/blog\/wp-json\/wp\/v2\/posts\/513\/revisions"}],"predecessor-version":[{"id":515,"href":"https:\/\/joost.vunderink.net\/blog\/wp-json\/wp\/v2\/posts\/513\/revisions\/515"}],"wp:attachment":[{"href":"https:\/\/joost.vunderink.net\/blog\/wp-json\/wp\/v2\/media?parent=513"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/joost.vunderink.net\/blog\/wp-json\/wp\/v2\/categories?post=513"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/joost.vunderink.net\/blog\/wp-json\/wp\/v2\/tags?post=513"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}