{
    "componentChunkName": "component---src-templates-post-js",
    "path": "/blog/2012/11/17/using-custom-jasmine-matchers-to-make-unit-tests-more-readable",
    "result": {"data":{"site":{"siteMetadata":{"title":"your friend Joel's digital garden","description":"Articles and notes from a collaborator at egghead.io. Musings on software, business, and life from a skilled virtual assistant.","author":{"name":"Joel Hooks"},"keywords":["Video Blogger"]}},"mdx":{"excerpt":"Image from purplemattfish I'm a stickler for the \"single assertion per test\" guideline. One of the pillars of good unit tests is readability. Multiple asserts undermine this principle and make tests that are more difficult to read…","fields":{"github":"https://github.com/joelhooks/joelhooks-com/tree/master/content/legacy_blog/2012-11-17-using-custom-jasmine-matchers-to-make-unit-tests-more-readable.markdown"},"body":"var _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"layout\": \"post\",\n  \"title\": \"Using Custom Jasmine Matchers to Make Unit Tests More Readable\",\n  \"date\": \"2012-11-17T00:00:00.000Z\",\n  \"comments\": true\n};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, mdx(\"span\", {\n    parentName: \"p\",\n    \"className\": \"gatsby-resp-image-wrapper\",\n    \"style\": {\n      \"position\": \"relative\",\n      \"display\": \"block\",\n      \"marginLeft\": \"auto\",\n      \"marginRight\": \"auto\",\n      \"maxWidth\": \"640px\"\n    }\n  }, \"\\n      \", mdx(\"a\", {\n    parentName: \"span\",\n    \"className\": \"gatsby-resp-image-link\",\n    \"href\": \"/static/8efaeef42932b0f28580a7aee0221f8b/c08c5/clean_and_dry.jpg\",\n    \"style\": {\n      \"display\": \"block\"\n    },\n    \"target\": \"_blank\",\n    \"rel\": \"noopener\"\n  }, \"\\n    \", mdx(\"span\", {\n    parentName: \"a\",\n    \"className\": \"gatsby-resp-image-background-image\",\n    \"style\": {\n      \"paddingBottom\": \"66.79536679536679%\",\n      \"position\": \"relative\",\n      \"bottom\": \"0\",\n      \"left\": \"0\",\n      \"backgroundImage\": \"url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAECA//EABcBAAMBAAAAAAAAAAAAAAAAAAABAwT/2gAMAwEAAhADEAAAAavJZrsyGf/EABcQAQEBAQAAAAAAAAAAAAAAAAEAERL/2gAIAQEAAQUCeJZxsNtv/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQIBAT8BJ//EABcQAAMBAAAAAAAAAAAAAAAAAAIQESL/2gAIAQEABj8C2Ndj/8QAGxAAAgMAAwAAAAAAAAAAAAAAAAERITFBUZH/2gAIAQEAAT8hd2sFJsgdZ1ySrjwUzRjrBj//2gAMAwEAAgADAAAAENzP/8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQMBAT8QSf/EABYRAQEBAAAAAAAAAAAAAAAAAAEQQf/aAAgBAgEBPxBGz//EABwQAQADAAIDAAAAAAAAAAAAAAEAESExUUFxgf/aAAgBAQABPxA3OzsK9ShEDOZj5HcFzKbVCnHme4lqkvMeIo0ZP//Z')\",\n      \"backgroundSize\": \"cover\",\n      \"display\": \"block\"\n    }\n  }), \"\\n  \", mdx(\"img\", {\n    parentName: \"a\",\n    \"className\": \"gatsby-resp-image-image\",\n    \"alt\": \"Clean and Dry\",\n    \"title\": \"Clean and Dry\",\n    \"src\": \"/static/8efaeef42932b0f28580a7aee0221f8b/c08c5/clean_and_dry.jpg\",\n    \"srcSet\": [\"/static/8efaeef42932b0f28580a7aee0221f8b/8356d/clean_and_dry.jpg 259w\", \"/static/8efaeef42932b0f28580a7aee0221f8b/bc760/clean_and_dry.jpg 518w\", \"/static/8efaeef42932b0f28580a7aee0221f8b/c08c5/clean_and_dry.jpg 640w\"],\n    \"sizes\": \"(max-width: 640px) 100vw, 640px\",\n    \"style\": {\n      \"width\": \"100%\",\n      \"height\": \"100%\",\n      \"margin\": \"0\",\n      \"verticalAlign\": \"middle\",\n      \"position\": \"absolute\",\n      \"top\": \"0\",\n      \"left\": \"0\"\n    },\n    \"loading\": \"lazy\",\n    \"decoding\": \"async\"\n  }), \"\\n  \"), \"\\n    \")), mdx(\"p\", null, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.flickr.com/photos/29601732@N06/3969905051/\"\n  }, \"Image from purplemattfish\")), mdx(\"p\", null, \"I'm a stickler for the \\\"single assertion per test\\\" guideline. One of the pillars of good unit tests is readability. Multiple asserts undermine this principle and make tests that are more difficult to read, understand, and maintain. A clean solution to this problem is to use custom Jasmine matchers in place of multiple assertions.\"), mdx(\"h2\", null, \"Keep it DRY, Even (Especially?) in Tests\"), mdx(\"p\", null, \"Consider the following:\"), mdx(\"p\", null, \"In our app, we recieve a \\\"split date\\\" object from our service. It returns a value in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"{year: 2012, month: 11, day: 17}\"), \" format. We have some functionality that will convert the format back and for to a JavaScript \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Date\"), \".\"), mdx(\"p\", null, \"This seems straight forward enough, but as it turns out we need to go the other direction as well:\"), mdx(\"p\", null, \"This is bothersome. We have two stacks of \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"expect\"), \" calls that are very similar, but different enough to require a bit more than a helper method. We definitely want to verify all of the properties of the results, but do we really need to do this individually? The short answer is 'no.'\"), mdx(\"h2\", null, \"Enter the Custom Matcher\"), mdx(\"p\", null, \"A custom matcher is nestled in a \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"beforeEach\"), \" function. This will cause Jasmine to load the matcher prior to EVERY \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"describe\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"it\"), \" in your test suite.\"), mdx(\"p\", null, \"Within the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"beforeEach\"), \" is \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"this.addMatcher\"), \" that takes an \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"object\"), \" whose properties are your actual custom matchers. In our example the 'toEqualDate' matcher is the only property, but you can add as many as you might need for your application.\"), mdx(\"p\", null, \"In the scope of the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"toEqualDate\"), \" function, we pass in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"expectedDate\"), \" parameter. This is the argument passed into \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"toEqualDate(myExpectedDate)\"), \". We also have access to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"this.actual\"), \" that is the argument passed into \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"expect(myActualDate)\"), \" within your test.\"), mdx(\"p\", null, \"The next important bit is the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"this.message\"), \" function that Jasmine will use to display any custom error messages. In this case we are returning two messages as appropriate. The first will return an invalid match, and the second will return a message if either object is not a valid date (if they are undefined, null, or incorrectly formatted).\"), mdx(\"p\", null, \"Finally the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"toEqualDate\"), \" function will return true or false based on the values we are comparing. If they are indeed valid \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Date\"), \" objects, it will compare them. If they are not, we return false.\"), mdx(\"p\", null, \"At the top of the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"beforeEach\"), \" we also have two utility methods to clean up our custom matcher.\"), mdx(\"h2\", null, \"Keeping it Clean and DRY\"), mdx(\"p\", null, \"I don't know about you, but these tests look a \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"lot\"), \" better to me. While the overall lines of code may have increased, we've created a reusable solution that can be used over and over again while not repeating ourselves. Our tests now have a single \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"expect\"), \" that is easy to understand and clearly expresses the intent of the test in an easy to read way.\"), mdx(\"h2\", null, \"Additional Reading\"), mdx(\"p\", null, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/pivotal/jasmine/wiki/Matchers\"\n  }, \"Official Documentation on Jasmine Matcher\")), mdx(\"p\", null, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://lostechies.com/derickbailey/2011/09/03/custom-jasmine-matchers-for-clarity-in-testing-backbone-js-models/\"\n  }, \"Custom Jasmine Matchers For Clarity In Testing Backbone.js Models\")), mdx(\"p\", null, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://testdrivenwebsites.com/2010/08/04/custom-jquery-matchers-in-jasmine/\"\n  }, \"Custom jQuery matchers in Jasmine\")));\n}\n;\nMDXContent.isMDXComponent = true;","frontmatter":{"title":"Using Custom Jasmine Matchers to Make Unit Tests More Readable","date":"November 17, 2012","banner":null,"slug":null,"keywords":null}}},"pageContext":{"id":"18235215-6af2-59bd-9937-823f7d7ca5a0","prev":{"id":"bd42a971-34e0-57d6-a11e-2d590093a742","parent":{"name":"2013-04-09-vim-adventures-a-fun-way-to-pick-up-some-basic-skills","sourceInstanceName":"legacy"},"excerpt":"Vim Adventures  is a fun browser based game that\nteaches basic VIM skills while adventuring. It is kind of silly, and can be a\nbit... frustrating... but that is the point. This is VIM after all! No pain, no\ngain ;)","fields":{"title":"VIM Adventures: A Fun Way to Pick up Some Basic Skills","slug":"blog/2013/04/09/vim-adventures-a-fun-way-to-pick-up-some-basic-skills","date":"2013-04-09T00:00:00.000Z"}},"next":{"id":"b28faa8b-8771-5e26-8e21-ad40debf0dce","parent":{"name":"2012-08-28-practical-object-oriented-design-in-ruby-is-a-really-good-book","sourceInstanceName":"legacy"},"excerpt":"I've been reading the Rough Cut of  Practical Object Oriented Design , and I have been absolutely enjoying every page. It isn't very often that a technical book comes along that really strikes me as a \"new classic,\" but this one qualifies.  Sandi…","fields":{"title":"Practical Object Oriented Design is Excellent","slug":"blog/2012/08/28/practical-object-oriented-design-in-ruby-is-a-really-good-book","date":"2012-08-28T00:00:00.000Z"}}}},
    "staticQueryHashes": ["1045846374"]}