{"id":378,"date":"2009-01-28T22:12:08","date_gmt":"2009-01-28T22:12:08","guid":{"rendered":"http:\/\/thekua.com\/atwork\/?p=378"},"modified":"2009-01-28T23:11:25","modified_gmt":"2009-01-28T23:11:25","slug":"controlling-time","status":"publish","type":"post","link":"https:\/\/thekua.com\/atwork\/2009\/01\/controlling-time\/","title":{"rendered":"Controlling Time"},"content":{"rendered":"<p><em>Disclaimer: This technique does not work outside of programming. Do not try this on your neighbours, kids or pets&#8230;<\/em><\/p>\n<p><strong>What&#8217;s wrong with time dependent tests?<\/strong><br \/>\nIt&#8217;s easy to write tests that are far too flaky and intermittent. Worse yet, a quick fix often results in putting a pause to tests that make them drag out longer and longer. Alternatively, unneeded complexity is added to try to do smart things to poll for tests to time out. <\/p>\n<p><strong>What can we do about it?<\/strong><br \/>\nI&#8217;m all about solutions, so I&#8217;m out about to outline the secret to controlling time (in at least unit tests). Here&#8217;s a situation you might recognise. Or not. Sorry to anyone vegetarian reading this entry. <\/p>\n<p>We have a class called <strong>Beef<\/strong> that knows when it&#8217;s past its prime using the <a href=\"http:\/\/joda-time.sourceforge.net\/\">Joda Time<\/a> libraries. <\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">package com.thekua.examples;\r\n\r\nimport org.joda.time.DateTime;\r\n\r\npublic class Beef {\r\n\tprivate final DateTime expiryDate;\r\n\r\n\tpublic Beef(DateTime expiryDate) {\r\n\t\tthis.expiryDate = expiryDate;\r\n\t}\r\n\t\r\n\tpublic boolean isPastItsPrime() {\r\n\t\tDateTime now = new DateTime(); \/\/ Notice this line?\r\n\t\treturn now.isAfter(expiryDate); \r\n\t}\r\n}<\/pre>\n<p>Surprise, surprise. We also have a unit test for it:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">package com.thekua.examples;\r\n\r\nimport static org.junit.Assert.assertTrue;\r\nimport org.joda.time.DateTime;\r\nimport org.junit.Test;\r\n\r\npublic class BeefTest {\r\n\t@Test\r\n\tpublic void shouldBePastItsPrimeWhenExpiryDateIsPast() throws Exception {\r\n\t\tint timeToPassForExpiry = 100;\r\n\t\t\r\n\t\tBeef beef = new Beef(new DateTime().plus(timeToPassForExpiry));\r\n\t\t\r\n\t\tThread.sleep(timeToPassForExpiry * 2); \/\/ Sleep? Bleh...\r\n\t\t\r\n\t\tassertTrue(beef.isPastItsPrime());\r\n\t}\r\n}<\/pre>\n<p><strong>Step 1: Contain time (in an object of course)<\/strong><br \/>\nThe first step is to contain all the use of time concepts behind an object. Don&#8217;t even try to call this class a <code>TimeProvider<\/code>. It&#8217;s a <code>Clock<\/code> okay? (I&#8217;m sure I used to call it that in the past as well, so don&#8217;t worry!). The responsibility of the <code>Clock<\/code> is to tell us the time. Here&#8217;s what it looks like:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">package com.thekua.examples;\r\n\r\nimport org.joda.time.DateTime;\r\n\r\npublic interface Clock {\r\n\tDateTime now();\r\n}<\/pre>\n<p>In order to support the system working as normally, we are going to introduce the <code>SystemClock<\/code>. I sometimes call this a <code>RealClock<\/code>. It looks a bit like this:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">package com.thekua.examples;\r\n\r\nimport org.joda.time.DateTime;\r\n\r\npublic class SystemClock implements Clock {\r\n\tpublic DateTime now() {\r\n\t\treturn new DateTime();\r\n\t}\r\n}<\/pre>\n<p>We are now going to let our <code>Beef<\/code> now depend on our <code>Clock<\/code> concept. It should now look like this:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">package com.thekua.examples;\r\n\r\nimport org.joda.time.DateTime;\r\n\r\npublic class Beef {\r\n\tprivate final DateTime expiryDate;\r\n\tprivate final Clock clock;\r\n\r\n\tpublic Beef(DateTime expiryDate, Clock clock) {\r\n\t\tthis.expiryDate = expiryDate;\r\n\t\tthis.clock = clock;\r\n\t}\r\n\t\r\n\tpublic boolean isPastItsPrime() {\r\n\t\tDateTime now = clock.now();\r\n\t\treturn now.isAfter(expiryDate); \r\n\t}\r\n}<\/pre>\n<p>If you wanted to, the step by step refactoring would look like:<\/p>\n<ol>\n<li>Replace <code>new DateTime()<\/code> with <code>new SystemClock().now()<\/code><\/li>\n<li>Replace new instance with field<\/li>\n<li>Instantiate new field in constructor<\/li>\n<\/ol>\n<p>We&#8217;d use the <code>RealClock<\/code> in both the code that creates the <code>Beef<\/code> as well as our test. Our test should look like&#8230;<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">package com.thekua.examples;\r\n\r\nimport static org.junit.Assert.assertTrue;\r\nimport org.junit.Test;\r\n\r\npublic class BeefTest {\r\n\t@Test\r\n\tpublic void shouldBePastItsPrimeWhenExpiryDateIsPast() throws Exception {\r\n\t\tint timeToPassForExpiry = 100;\r\n\t\tSystemClock clock = new SystemClock();\r\n\t\t\r\n\t\tBeef beef = new Beef(clock.now().plus(timeToPassForExpiry), clock);\r\n\t\t\r\n\t\tThread.sleep(timeToPassForExpiry * 2);\r\n\t\t\r\n\t\tassertTrue(beef.isPastItsPrime());\r\n\t}\r\n}<\/pre>\n<p><strong>Step 2: Change the flow of time in tests<\/strong><br \/>\nNow that we have the production code dependent on an abstract notion of time, and our test still working, we now want to substitute the <code>RealClock<\/code> with another object that allows us to shift time for tests. I&#8217;m going to call it the <code>ControlledClock<\/code>. Its responsibility is to control the flow of time. For the purposes of this example, we&#8217;re only going to allow time to flow forward (and ensure tests use relative times instead of absolute). You might vary it if you needed very precise dates and times. Note the new method <code>forwardTimeInMillis<\/code>.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">package com.thekua.examples;\r\n\r\nimport org.joda.time.DateTime;\r\n\r\npublic class ControlledClock implements Clock {\r\n\tprivate DateTime now = new DateTime();\r\n\r\n\tpublic DateTime now() {\r\n\t\treturn now;\r\n\t}\t\r\n\t\r\n\tpublic void forwardTimeInMillis(long milliseconds) {\r\n\t\tnow = now.plus(milliseconds);\r\n\t}\r\n}<\/pre>\n<p>Now we can use this new concept in our tests, and replace the way that we previously forwarded time (with the <code>Thread.sleep<\/code>) with our new class. Here&#8217;s what our final test looks like now:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">package com.thekua.examples;\r\n\r\nimport static org.junit.Assert.assertTrue;\r\nimport org.junit.Test;\r\n\r\npublic class BeefTest {\r\n\t@Test\r\n\tpublic void shouldBePastItsPrimeWhenExpiryDateIsPast() throws Exception {\r\n\t\tint timeToPassForExpiry = 100;\r\n\t\tControlledClock clock = new ControlledClock();\r\n\t\t\r\n\t\tBeef beef = new Beef(clock.now().plus(timeToPassForExpiry), clock);\r\n\t\t\r\n\t\tclock.forwardTimeInMillis(timeToPassForExpiry * 2);\r\n\t\t\r\n\t\tassertTrue(beef.isPastItsPrime());\r\n\t}\r\n}\r\n<\/pre>\n<p>We can even further improve this test to be more specific by forwarding time by simply adding one rather than multiplying twice. <\/p>\n<p><strong>Step 3: Save time (and get some real sleep)<\/strong><br \/>\nAlthough this is a pretty trivial example of a single use of time dependent tests, it shouldn&#8217;t take too much effort to introduce this concept to any classes that depend on time. Not only will you save yourself heart-ache with either flaky, broken tests, but you should also save yourself the waiting time you&#8217;d otherwise need to introduce, leading to faster test execution, and that wonderful thing of fast feedback. <\/p>\n<p>Enjoy! Let me know what you thought of this by leaving a comment.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Disclaimer: This technique does not work outside of programming. Do not try this on your neighbours, kids or pets&#8230; What&#8217;s wrong with time dependent tests? It&#8217;s easy to write tests that are far too flaky and intermittent. Worse yet, a quick fix often results in putting a pause to tests that make them drag out [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,35,12],"tags":[],"class_list":["post-378","post","type-post","status-publish","format-standard","hentry","category-development","category-java","category-testing","post-preview"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Controlling Time - patkua@work<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/thekua.com\/atwork\/2009\/01\/controlling-time\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Controlling Time - patkua@work\" \/>\n<meta property=\"og:description\" content=\"Disclaimer: This technique does not work outside of programming. Do not try this on your neighbours, kids or pets&#8230; What&#8217;s wrong with time dependent tests? It&#8217;s easy to write tests that are far too flaky and intermittent. Worse yet, a quick fix often results in putting a pause to tests that make them drag out [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/thekua.com\/atwork\/2009\/01\/controlling-time\/\" \/>\n<meta property=\"og:site_name\" content=\"patkua@work\" \/>\n<meta property=\"article:published_time\" content=\"2009-01-28T22:12:08+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2009-01-28T23:11:25+00:00\" \/>\n<meta name=\"author\" content=\"Patrick\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@patkua\" \/>\n<meta name=\"twitter:site\" content=\"@patkua\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Patrick\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/thekua.com\\\/atwork\\\/2009\\\/01\\\/controlling-time\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/thekua.com\\\/atwork\\\/2009\\\/01\\\/controlling-time\\\/\"},\"author\":{\"name\":\"Patrick\",\"@id\":\"https:\\\/\\\/thekua.com\\\/atwork\\\/#\\\/schema\\\/person\\\/c942203c9ed3ff9e21c6c49a996ea3ae\"},\"headline\":\"Controlling Time\",\"datePublished\":\"2009-01-28T22:12:08+00:00\",\"dateModified\":\"2009-01-28T23:11:25+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/thekua.com\\\/atwork\\\/2009\\\/01\\\/controlling-time\\\/\"},\"wordCount\":875,\"commentCount\":11,\"articleSection\":[\"Development\",\"Java\",\"Testing\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/thekua.com\\\/atwork\\\/2009\\\/01\\\/controlling-time\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/thekua.com\\\/atwork\\\/2009\\\/01\\\/controlling-time\\\/\",\"url\":\"https:\\\/\\\/thekua.com\\\/atwork\\\/2009\\\/01\\\/controlling-time\\\/\",\"name\":\"Controlling Time - patkua@work\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/thekua.com\\\/atwork\\\/#website\"},\"datePublished\":\"2009-01-28T22:12:08+00:00\",\"dateModified\":\"2009-01-28T23:11:25+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/thekua.com\\\/atwork\\\/#\\\/schema\\\/person\\\/c942203c9ed3ff9e21c6c49a996ea3ae\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/thekua.com\\\/atwork\\\/2009\\\/01\\\/controlling-time\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/thekua.com\\\/atwork\\\/2009\\\/01\\\/controlling-time\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/thekua.com\\\/atwork\\\/2009\\\/01\\\/controlling-time\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/thekua.com\\\/atwork\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Controlling Time\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/thekua.com\\\/atwork\\\/#website\",\"url\":\"https:\\\/\\\/thekua.com\\\/atwork\\\/\",\"name\":\"patkua@work\",\"description\":\"The intersection of technology and leadership\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/thekua.com\\\/atwork\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/thekua.com\\\/atwork\\\/#\\\/schema\\\/person\\\/c942203c9ed3ff9e21c6c49a996ea3ae\",\"name\":\"Patrick\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/2ef85a5f91c2aac13efb3ac90077b4db7f8883cafd6e60f2bcecba6b092d4011?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/2ef85a5f91c2aac13efb3ac90077b4db7f8883cafd6e60f2bcecba6b092d4011?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/2ef85a5f91c2aac13efb3ac90077b4db7f8883cafd6e60f2bcecba6b092d4011?s=96&d=mm&r=g\",\"caption\":\"Patrick\"},\"sameAs\":[\"http:\\\/\\\/thekua.com\\\/atwork\"],\"url\":\"https:\\\/\\\/thekua.com\\\/atwork\\\/author\\\/patrick\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Controlling Time - patkua@work","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/thekua.com\/atwork\/2009\/01\/controlling-time\/","og_locale":"en_US","og_type":"article","og_title":"Controlling Time - patkua@work","og_description":"Disclaimer: This technique does not work outside of programming. Do not try this on your neighbours, kids or pets&#8230; What&#8217;s wrong with time dependent tests? It&#8217;s easy to write tests that are far too flaky and intermittent. Worse yet, a quick fix often results in putting a pause to tests that make them drag out [&hellip;]","og_url":"https:\/\/thekua.com\/atwork\/2009\/01\/controlling-time\/","og_site_name":"patkua@work","article_published_time":"2009-01-28T22:12:08+00:00","article_modified_time":"2009-01-28T23:11:25+00:00","author":"Patrick","twitter_card":"summary_large_image","twitter_creator":"@patkua","twitter_site":"@patkua","twitter_misc":{"Written by":"Patrick","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/thekua.com\/atwork\/2009\/01\/controlling-time\/#article","isPartOf":{"@id":"https:\/\/thekua.com\/atwork\/2009\/01\/controlling-time\/"},"author":{"name":"Patrick","@id":"https:\/\/thekua.com\/atwork\/#\/schema\/person\/c942203c9ed3ff9e21c6c49a996ea3ae"},"headline":"Controlling Time","datePublished":"2009-01-28T22:12:08+00:00","dateModified":"2009-01-28T23:11:25+00:00","mainEntityOfPage":{"@id":"https:\/\/thekua.com\/atwork\/2009\/01\/controlling-time\/"},"wordCount":875,"commentCount":11,"articleSection":["Development","Java","Testing"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/thekua.com\/atwork\/2009\/01\/controlling-time\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/thekua.com\/atwork\/2009\/01\/controlling-time\/","url":"https:\/\/thekua.com\/atwork\/2009\/01\/controlling-time\/","name":"Controlling Time - patkua@work","isPartOf":{"@id":"https:\/\/thekua.com\/atwork\/#website"},"datePublished":"2009-01-28T22:12:08+00:00","dateModified":"2009-01-28T23:11:25+00:00","author":{"@id":"https:\/\/thekua.com\/atwork\/#\/schema\/person\/c942203c9ed3ff9e21c6c49a996ea3ae"},"breadcrumb":{"@id":"https:\/\/thekua.com\/atwork\/2009\/01\/controlling-time\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/thekua.com\/atwork\/2009\/01\/controlling-time\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/thekua.com\/atwork\/2009\/01\/controlling-time\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/thekua.com\/atwork\/"},{"@type":"ListItem","position":2,"name":"Controlling Time"}]},{"@type":"WebSite","@id":"https:\/\/thekua.com\/atwork\/#website","url":"https:\/\/thekua.com\/atwork\/","name":"patkua@work","description":"The intersection of technology and leadership","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/thekua.com\/atwork\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/thekua.com\/atwork\/#\/schema\/person\/c942203c9ed3ff9e21c6c49a996ea3ae","name":"Patrick","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/2ef85a5f91c2aac13efb3ac90077b4db7f8883cafd6e60f2bcecba6b092d4011?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/2ef85a5f91c2aac13efb3ac90077b4db7f8883cafd6e60f2bcecba6b092d4011?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/2ef85a5f91c2aac13efb3ac90077b4db7f8883cafd6e60f2bcecba6b092d4011?s=96&d=mm&r=g","caption":"Patrick"},"sameAs":["http:\/\/thekua.com\/atwork"],"url":"https:\/\/thekua.com\/atwork\/author\/patrick\/"}]}},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/thekua.com\/atwork\/wp-json\/wp\/v2\/posts\/378","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thekua.com\/atwork\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thekua.com\/atwork\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thekua.com\/atwork\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/thekua.com\/atwork\/wp-json\/wp\/v2\/comments?post=378"}],"version-history":[{"count":9,"href":"https:\/\/thekua.com\/atwork\/wp-json\/wp\/v2\/posts\/378\/revisions"}],"predecessor-version":[{"id":389,"href":"https:\/\/thekua.com\/atwork\/wp-json\/wp\/v2\/posts\/378\/revisions\/389"}],"wp:attachment":[{"href":"https:\/\/thekua.com\/atwork\/wp-json\/wp\/v2\/media?parent=378"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thekua.com\/atwork\/wp-json\/wp\/v2\/categories?post=378"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thekua.com\/atwork\/wp-json\/wp\/v2\/tags?post=378"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}