{"id":755,"date":"2018-02-15T16:28:56","date_gmt":"2018-02-15T16:28:56","guid":{"rendered":"https:\/\/devexperts.com\/blog\/?p=755"},"modified":"2022-07-28T13:53:04","modified_gmt":"2022-07-28T13:53:04","slug":"time-machine-for-java","status":"publish","type":"post","link":"https:\/\/devexperts.com\/blog\/time-machine-for-java\/","title":{"rendered":"Time Machine for Java"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\" id=\"h-this-article-describes-a-tool-developed-to-support-unit-testing-of-time-dependent-logic-in-java-applications-the-tool-helps-control-the-quality-of-trading-platforms-and-other-complex-and-or-concurrent-systems\">This article describes a tool developed to support unit-testing of time-dependent logic in Java applications. The tool helps control the quality of trading platforms, and other complex and\/or concurrent systems.<\/h2>\n\n\n\n<div class=\"wp-block-devexperts-custom-thumbnail\"><figure><picture><source media=\"(max-width: 639px)\" data-srcset=\"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/Index-postcard-big-1148-X-1148-574x574.png 2x, https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/Index-postcard-big-1148-X-1148-300x300.png 1x\"\/><source media=\"(min-width: 640px) and (max-width: 767px)\" data-srcset=\"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/Post-inner-banner-2336x1314-1-1168x657.png 2x, https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/Post-inner-banner-2336x1314-1-600x338.png 1x\"\/><source media=\"(min-width: 768px) and (max-width: 1023px)\" data-srcset=\"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/Post-inner-banner-2336x1314-1-1168x657.png 2x, https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/Post-inner-banner-2336x1314-1-728x410.png 1x\"\/><source media=\"(min-width: 1024px) and (max-width: 1279px)\" data-srcset=\"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/Post-inner-banner-2336x1314-1-1168x657.png 1x, https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/Post-inner-banner-2336x1314-1-690x388.png 1x\"\/><source media=\"(min-width: 1280px)\" data-srcset=\"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/Post-inner-banner-2336x1314-1-1752x986.png 2x,\n\t\t\t\thttps:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/Post-inner-banner-2336x1314-1-1752x986.png 1.5x,\n\t\t\t\thttps:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/Post-inner-banner-2336x1314-1-870x489.png 1x\"\/><img decoding=\"async\" class=\"singleThumbnail lazyload\" src=\"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/Post-inner-banner-2336x1314-1-1024x576.png\" data-src=\"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/Post-inner-banner-2336x1314-1-870x489.png\"\/><\/picture><\/figure><\/div>\n\n\n\n<p>It is not always simple to write unit tests for time-dependent functionality. In straightforward situations simply replacing a method which returns the current time with a custom implementation [<a href=\"#footnote-1\">1<\/a>,<a href=\"#footnote-2\">2<\/a>] will work.<\/p>\n\n\n\n<p>Here is a simple method counting the number of days before the end of the world:<\/p>\n\n\n<pre><code class='codeBlock java'>fun daysBeforeDoom() {<br \/>\n    return doomTime - System.currentTimeMillis()) \/ millisInDay<br \/>\n}<\/code><\/pre>\n\n\n\n<p>Replacing all invocations of <span style=\"font-family: monospace;\">System.currentTimeMillis()<\/span> with either an existing tool [<a href=\"#footnote-1\">1<\/a>,<a href=\"#footnote-2\">2<\/a>] or by writing a system specific&nbsp;code transformer using the ASM framework [<a href=\"#footnote-3\">3<\/a>] or AspectJ [<a href=\"#footnote-4\">4<\/a>] will often suffice.<\/p>\n\n\n\n<p>There are other cases where this approach is insufficient. Imagine we want our code to wake up each day and display \u201cN days left until the doomsday\u201d as in the following code snippet.<\/p>\n\n\n<pre><code class='codeBlock java'>while (true) {<br \/>\n    Thread.sleep(ONE_DAY)<br \/>\n    println(\u201c${daysBeforeDoom()} days left till the doomsday\u201d)<br \/>\n}<\/code><\/pre>\n\n\n\n<p>How can we test this code? How do we assert that it is invoked every day and that it displays the correct message? Using the simple approach described above and replacing <span style=\"font-family: monospace;\">System.currentTimeMillis()<\/span> only allows us to test the correctness of the message. We would need to wait for a whole day to test the time span.<\/p>\n\n\n\n<p>It is practically impossible to test such code without additional tools. Let\u2019s try to create one.<\/p>\n\n\n\n<p>Currently we have two methods that return the current time: <span style=\"font-family: monospace;\">System.currentTimeMillis()<\/span> and <span style=\"font-family: monospace;\">System.nanoTime()<\/span>. We also have several time-dependent methods that wait for an event or may timeout: <span style=\"font-family: monospace;\">Thread.sleep()<\/span>, <span style=\"font-family: monospace;\">Object.wait()<\/span>, and <span style=\"font-family: monospace;\">LockSupport.park()<\/span>.<\/p>\n\n\n\n<p>We want to create a new method <span style=\"font-family: monospace;\">increaseTime()<\/span> which can change the current time and wake up any waiting threads with a timeout.<\/p>\n\n\n\n<p>To enable this, all of the existing time-dependent methods will need to be replaced with custom implementations. Let\u2019s see how this may work..<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-test-example\">Test example:<\/h2>\n\n\n<pre><code class='codeBlock java'>increaseTime(ONE_DAY)<br \/>\ncheckMessage()<\/code><\/pre>\n\n\n\n<p>This creates a potential race condition between our check message and the actual time it takes to complete the print operation.&nbsp;Of course, one approach is to add a pause:<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-repaired-test\">Repaired test:<\/h2>\n\n\n<pre><code class='codeBlock java'>increaseTime(ONE_DAY)<br \/>\nThread.sleep(500 \/*ms*\/)<br \/>\ncheckMessage()<\/code><\/pre>\n\n\n\n<p>In regular practice, this test will almost always work but it is not guaranteed that <span style=\"font-family: monospace;\">checkMessage()<\/span> is invoked after the message is printed. This can occur due to the complexity of the test logic or simply having the code executed on an overcommitted server. You might be tempted to increase the timeout but this makes the tests slower and still offers no guarantee of correctness.<\/p>\n\n\n\n<p>Instead we need a special method that waits until all woken up threads have been completed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-test-we-would-like-to-write\">Test we would like to write:<\/h2>\n\n\n<pre><code class='codeBlock java'>increaseTime(ONE_DAY)<br \/>\nwaitUntilThreadsAreFrozen(1_000\/*ms, timeout*\/)<br \/>\ncheckMessage()<\/code><\/pre>\n\n\n\n<p>The inherent challenge is that&nbsp;we want to support all time-dependent methods during testing but we also want a <span style=\"font-family: monospace;\">waitUntilThreadsAreFrozen()<\/span> method and it is not simple to support both.<\/p>\n\n\n\n<p>Our solution is implemented in a special tool at Devexperts for testing time-dependent logic called time-test [<a href=\"#footnote-5\">5<\/a>].<\/p>\n\n\n\n<p>Let\u2019s look at how it works.<\/p>\n\n\n\n<p>Time-test is implemented as a Java agent. To utilize it you should add javaagent:timetest.jar and include it in the classpath. The tool transforms byte-code and replaces all time-dependent method invocations with our specific implementations. However, writing a good java agent sometimes is not simple so we have developed a JAgent framework [<a href=\"#footnote-6\">6<\/a>] to simplify java agents development.<\/p>\n\n\n\n<p>When creating your time dependent tests you should enable TestTimeProvider. It implements all required&nbsp;time-dependent methods (<span style=\"font-family: monospace;\">System.currentTimeMillis()<\/span>, <span style=\"font-family: monospace;\">Thread.sleep()<\/span>, <span style=\"font-family: monospace;\">Object.wait()<\/span>, <span style=\"font-family: monospace;\">LockSupport.park()<\/span>, &#8230;) and overrides their default implementations.&nbsp;In most tests, you do not need to actually manage the underlying time so the tool internally continues to utilize the default time-dependent methods wrapped inside the overloaded method. After starting TestTimeProvider you can use the <span style=\"font-family: monospace;\">TestTimeProvider.setTime(), TestTimeProvider.increaseTime()<\/span> and <span style=\"font-family: monospace;\">TestTimeProvider.waitUntilThreadsAreFrozen()<\/span> methods.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-timeprovider-java\">TimeProvider.java:<\/h2>\n\n\n<pre><code class='codeBlock java'>long timeMillis();<br \/>\nlong nanoTime();<br \/>\nvoid sleep(long millis) throws InterruptedException;<br \/>\nvoid sleep(long millis, int nanos) throws InterruptedException;<br \/>\nvoid waitOn(Object monitor, long millis) throws InterruptedException;<br \/>\nvoid waitOn(Object monitor, long millis, int nanos) throws InterruptedException;<br \/>\nvoid notifyAll(Object monitor);<br \/>\nvoid notify(Object monitor);<br \/>\nvoid park(boolean isAbsolute, long time);<br \/>\nvoid unpark(Object thread);<\/code><\/pre>\n\n\n\n<p>As previously described, the primary challenge of the TestTimeProvider implementation is supporting both the time-dependent method along side the additional <span style=\"font-family: monospace;\">waitUntilThreadsAreFrozen()<\/span> method. On every time change all required threads are marked as resumed and only then are woken. At the same time, <span style=\"font-family: monospace;\">waitUntilThreadsAreFrozen()<\/span> waits until all threads are in a waiting state and none of them are marked as resumed. With this approach threads will wake up, reset their resumed mark, perform their task and then return to a waiting state before waitUntilThreadsAreFrozen will recognize it as complete.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-test-with-testtimeprovider\">Test with TestTimeProvider:<\/h2>\n\n\n<pre><code class='codeBlock java'>@Before<br \/>\npublic void setup() {<br \/>\n    \/\/ Use TestTimeProvider for this test<br \/>\n    TestTimeProvider.start(\/* initial time could be passed here *\/);<br \/>\n}<\/p>\n<p>@After<br \/>\npublic void reset() {<br \/>\n    \/\/ Reset time provider to default after the test execution<br \/>\n    TestTimeProvider.reset();<br \/>\n}<\/p>\n<p>@Test<br \/>\npublic void test() {<br \/>\n    runMyConcurrentApplication();<br \/>\n    TestTimeProvider.increaseTime(60_000 \/*ms*\/);<br \/>\n    TestTimeProvider.waitUntilThreadsAreFrozen(1_000 \/*ms*\/);<br \/>\n    checkMyApplicationState();<br \/>\n}<\/code><\/pre>\n\n\n\n<p>We hope that the time-test tool will make your life easier. The tool is open-sourced and available on GitHub [<a href=\"#footnote-5\">5<\/a>].<\/p>\n\n\n\n<p>Happy testing!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-references\">References:<\/h2>\n\n\n\n<ol class=\"wp-block-list\"><li><a name=\"footnote-1\"><\/a><a href=\"https:\/\/github.com\/TOPdesk\/time-transformer-agent\/\">https:\/\/github.com\/TOPdesk\/time-transformer-agent\/<\/a><\/li><li><a name=\"footnote-2\"><\/a><a href=\"https:\/\/stackoverflow.com\/questions\/2001671\/override-java-system-currenttimemillis-for-testing-time-sensitive-code\">https:\/\/stackoverflow.com\/questions\/2001671\/override-java-system-currenttimemillis-for-testing-time-sensitive-code<\/a><\/li><li><a name=\"footnote-3\"><\/a><a href=\"http:\/\/asm.ow2.org\/\">http:\/\/asm.ow2.org\/<\/a><\/li><li><a name=\"footnote-4\"><\/a><a href=\"https:\/\/www.eclipse.org\/aspectj\/\">https:\/\/www.eclipse.org\/aspectj\/<\/a><\/li><li><a name=\"footnote-5\"><\/a><a href=\"https:\/\/github.com\/Devexperts\/time-test\">https:\/\/github.com\/Devexperts\/time-test<\/a><\/li><li><a name=\"footnote-6\"><\/a><a href=\"https:\/\/github.com\/Devexperts\/jagent\">https:\/\/github.com\/Devexperts\/jagent<\/a><\/li><\/ol>\n","protected":false},"excerpt":{"rendered":"<p>This article describes a tool developed to support unit-testing of time-dependent logic in Java applications. The tool helps control the &hellip; <\/p>\n","protected":false},"author":7,"featured_media":1454,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2020],"tags":[64,38,37],"class_list":["post-755","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-fintech","tag-concurrent-programming","tag-data-races","tag-deadlocks"],"acf":{"nifty_post_card_image":4349,"nifty_post_card_index_big":4352,"nifty_post_inner_image":4351,"nifty_post_card_banner":4350},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.2) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Time Machine for Unit-Testing on Java \u2013 Devexperts Blog<\/title>\n<meta name=\"description\" content=\"Our open-sourced tool for unit-testing of time-dependent logic in Java applications helps control the quality of concurrent software systems.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/devexperts.com\/blog\/time-machine-for-java\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Time Machine for Java\" \/>\n<meta property=\"og:description\" content=\"Our open-sourced tool for unit-testing of time-dependent logic in Java applications helps control the quality of concurrent software systems.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/devexperts.com\/blog\/time-machine-for-java\/\" \/>\n<meta property=\"og:site_name\" content=\"Devexperts Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/devexperts\/\" \/>\n<meta property=\"article:published_time\" content=\"2018-02-15T16:28:56+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-07-28T13:53:04+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/timemachine.png\" \/>\n\t<meta property=\"og:image:width\" content=\"3840\" \/>\n\t<meta property=\"og:image:height\" content=\"701\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Nikita Koval\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@devexperts\" \/>\n<meta name=\"twitter:site\" content=\"@devexperts\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Nikita Koval\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":[\"Article\",\"BlogPosting\"],\"@id\":\"https:\/\/devexperts.com\/blog\/time-machine-for-java\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/devexperts.com\/blog\/time-machine-for-java\/\"},\"author\":{\"name\":\"Nikita Koval\"},\"headline\":\"Time Machine for Java\",\"datePublished\":\"2018-02-15T16:28:56+00:00\",\"dateModified\":\"2022-07-28T13:53:04+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/devexperts.com\/blog\/time-machine-for-java\/\"},\"wordCount\":917,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/devexperts.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/devexperts.com\/blog\/time-machine-for-java\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/timemachine.png\",\"keywords\":[\"concurrent programming\",\"data races\",\"deadlocks\"],\"articleSection\":[\"Fintech\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/devexperts.com\/blog\/time-machine-for-java\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/devexperts.com\/blog\/time-machine-for-java\/\",\"url\":\"https:\/\/devexperts.com\/blog\/time-machine-for-java\/\",\"name\":\"Time Machine for Unit-Testing on Java \u2013 Devexperts Blog\",\"isPartOf\":{\"@id\":\"https:\/\/devexperts.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/devexperts.com\/blog\/time-machine-for-java\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/devexperts.com\/blog\/time-machine-for-java\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/timemachine.png\",\"datePublished\":\"2018-02-15T16:28:56+00:00\",\"dateModified\":\"2022-07-28T13:53:04+00:00\",\"description\":\"Our open-sourced tool for unit-testing of time-dependent logic in Java applications helps control the quality of concurrent software systems.\",\"breadcrumb\":{\"@id\":\"https:\/\/devexperts.com\/blog\/time-machine-for-java\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/devexperts.com\/blog\/time-machine-for-java\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/devexperts.com\/blog\/time-machine-for-java\/#primaryimage\",\"url\":\"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/timemachine.png\",\"contentUrl\":\"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/timemachine.png\",\"width\":3840,\"height\":701},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/devexperts.com\/blog\/time-machine-for-java\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/devexperts.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Time Machine for Java\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/devexperts.com\/blog\/#website\",\"url\":\"https:\/\/devexperts.com\/blog\/\",\"name\":\"Devexperts Blog\",\"description\":\"We make complex finance ideas on technology, innovation and business simple\",\"publisher\":{\"@id\":\"https:\/\/devexperts.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/devexperts.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/devexperts.com\/blog\/#organization\",\"name\":\"Devexperts LLC\",\"url\":\"https:\/\/devexperts.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/devexperts.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/devexperts.com\/blog\/app\/uploads\/2019\/08\/DX-logo.png\",\"contentUrl\":\"https:\/\/devexperts.com\/blog\/app\/uploads\/2019\/08\/DX-logo.png\",\"width\":167,\"height\":30,\"caption\":\"Devexperts LLC\"},\"image\":{\"@id\":\"https:\/\/devexperts.com\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/devexperts\/\",\"https:\/\/x.com\/devexperts\",\"https:\/\/www.linkedin.com\/company\/devexperts\",\"https:\/\/www.youtube.com\/channel\/UCF3FRmes2KrcVsTXQ1aAB5w\/featured\"]}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Time Machine for Unit-Testing on Java \u2013 Devexperts Blog","description":"Our open-sourced tool for unit-testing of time-dependent logic in Java applications helps control the quality of concurrent software systems.","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:\/\/devexperts.com\/blog\/time-machine-for-java\/","og_locale":"en_US","og_type":"article","og_title":"Time Machine for Java","og_description":"Our open-sourced tool for unit-testing of time-dependent logic in Java applications helps control the quality of concurrent software systems.","og_url":"https:\/\/devexperts.com\/blog\/time-machine-for-java\/","og_site_name":"Devexperts Blog","article_publisher":"https:\/\/www.facebook.com\/devexperts\/","article_published_time":"2018-02-15T16:28:56+00:00","article_modified_time":"2022-07-28T13:53:04+00:00","og_image":[{"width":3840,"height":701,"url":"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/timemachine.png","type":"image\/png"}],"author":"Nikita Koval","twitter_card":"summary_large_image","twitter_creator":"@devexperts","twitter_site":"@devexperts","twitter_misc":{"Written by":"Nikita Koval","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":["Article","BlogPosting"],"@id":"https:\/\/devexperts.com\/blog\/time-machine-for-java\/#article","isPartOf":{"@id":"https:\/\/devexperts.com\/blog\/time-machine-for-java\/"},"author":{"name":"Nikita Koval"},"headline":"Time Machine for Java","datePublished":"2018-02-15T16:28:56+00:00","dateModified":"2022-07-28T13:53:04+00:00","mainEntityOfPage":{"@id":"https:\/\/devexperts.com\/blog\/time-machine-for-java\/"},"wordCount":917,"commentCount":0,"publisher":{"@id":"https:\/\/devexperts.com\/blog\/#organization"},"image":{"@id":"https:\/\/devexperts.com\/blog\/time-machine-for-java\/#primaryimage"},"thumbnailUrl":"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/timemachine.png","keywords":["concurrent programming","data races","deadlocks"],"articleSection":["Fintech"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/devexperts.com\/blog\/time-machine-for-java\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/devexperts.com\/blog\/time-machine-for-java\/","url":"https:\/\/devexperts.com\/blog\/time-machine-for-java\/","name":"Time Machine for Unit-Testing on Java \u2013 Devexperts Blog","isPartOf":{"@id":"https:\/\/devexperts.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/devexperts.com\/blog\/time-machine-for-java\/#primaryimage"},"image":{"@id":"https:\/\/devexperts.com\/blog\/time-machine-for-java\/#primaryimage"},"thumbnailUrl":"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/timemachine.png","datePublished":"2018-02-15T16:28:56+00:00","dateModified":"2022-07-28T13:53:04+00:00","description":"Our open-sourced tool for unit-testing of time-dependent logic in Java applications helps control the quality of concurrent software systems.","breadcrumb":{"@id":"https:\/\/devexperts.com\/blog\/time-machine-for-java\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/devexperts.com\/blog\/time-machine-for-java\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/devexperts.com\/blog\/time-machine-for-java\/#primaryimage","url":"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/timemachine.png","contentUrl":"https:\/\/devexperts.com\/blog\/app\/uploads\/2018\/02\/timemachine.png","width":3840,"height":701},{"@type":"BreadcrumbList","@id":"https:\/\/devexperts.com\/blog\/time-machine-for-java\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/devexperts.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Time Machine for Java"}]},{"@type":"WebSite","@id":"https:\/\/devexperts.com\/blog\/#website","url":"https:\/\/devexperts.com\/blog\/","name":"Devexperts Blog","description":"We make complex finance ideas on technology, innovation and business simple","publisher":{"@id":"https:\/\/devexperts.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/devexperts.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/devexperts.com\/blog\/#organization","name":"Devexperts LLC","url":"https:\/\/devexperts.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/devexperts.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/devexperts.com\/blog\/app\/uploads\/2019\/08\/DX-logo.png","contentUrl":"https:\/\/devexperts.com\/blog\/app\/uploads\/2019\/08\/DX-logo.png","width":167,"height":30,"caption":"Devexperts LLC"},"image":{"@id":"https:\/\/devexperts.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/devexperts\/","https:\/\/x.com\/devexperts","https:\/\/www.linkedin.com\/company\/devexperts","https:\/\/www.youtube.com\/channel\/UCF3FRmes2KrcVsTXQ1aAB5w\/featured"]}]}},"_links":{"self":[{"href":"https:\/\/devexperts.com\/blog\/wp-json\/wp\/v2\/posts\/755","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devexperts.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devexperts.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devexperts.com\/blog\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/devexperts.com\/blog\/wp-json\/wp\/v2\/comments?post=755"}],"version-history":[{"count":37,"href":"https:\/\/devexperts.com\/blog\/wp-json\/wp\/v2\/posts\/755\/revisions"}],"predecessor-version":[{"id":4701,"href":"https:\/\/devexperts.com\/blog\/wp-json\/wp\/v2\/posts\/755\/revisions\/4701"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devexperts.com\/blog\/wp-json\/wp\/v2\/media\/1454"}],"wp:attachment":[{"href":"https:\/\/devexperts.com\/blog\/wp-json\/wp\/v2\/media?parent=755"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devexperts.com\/blog\/wp-json\/wp\/v2\/categories?post=755"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devexperts.com\/blog\/wp-json\/wp\/v2\/tags?post=755"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}