If you're using expectations and Joda Time, you now have the ability to freeze time in bare expectations (version 1.4.16 and above). The following code demonstrates how you can use the freeze-time macro to set the time, verify anything you need, and allow time to be reset for you.
Under the covers freeze-time is setting the current millis using the DateTime you specify, running your code and resetting the current millis in a finally. As a result, after your code finishes executing, even if finishing involves throwing an exception, the millis of Joda Time will be set back to working as you'd expect.
The freeze-time macro can be used in both the expected and actual forms, and can be nested if you need to set the time multiple times within a single expectation.
Showing posts with label joda. Show all posts
Showing posts with label joda. Show all posts
Thursday, November 01, 2012
Tuesday, May 29, 2012
Clojure: Freezing Time in expectations
Don't do this, this blog post is out-dated. You want this: http://blog.jayfields.com/2012/11/clojure-freezing-time-added-to.html
The current version of expectations (1.4.3) contains support for freezing time within an expectations scenario. I already put this information out in a previous blog entry, and I'm going to use the same examples here.
The following code is a test I was working on at work:
The following code would have resulted in a passing test:
Therefore, expectations has been modified to take a :freeze-time parameter as part of a scenario definition. The :freeze-time parameter can be a string or a boolean - when specifying a string, anything parse-able by Joda will do; if you specify a boolean time will simply be stopped at the moment of execution.
With :freeze-time available we can rewrite the above test in the following way:
I believe the domain related code does a better job of demonstrating the point; however, the following examples are available if you'd like something simplified.
The current version of expectations (1.4.3) contains support for freezing time within an expectations scenario. I already put this information out in a previous blog entry, and I'm going to use the same examples here.
The following code is a test I was working on at work:
(scenario
(handle-fill (build PartialFill))
(expect {:px 10 :size 33 :time 1335758400000} (first @fills)))
The test builds a PartialFill domain object, and passes it to handle-fill. The handle-fill fn converts the domain object to a map and conj's the new map onto the fills vector (which is an atom). The above test would fail due to the time not being frozen, and the traditional way to deal with this issue was to change the test to use (in ..) and ignore the :time key-value pair.
The following code would have resulted in a passing test:
(scenario
(handle-fill (build PartialFill))
(expect {:px 10 :size 33} (in (first @fills))))
The above code is fine, as long as you're not interested in verifying the time; however, things get a lot uglier if you do want to verify time. The following code freezes (joda) time, allowing for time verification:
(scenario
(DateTimeUtils/setCurrentMillisFixed 100)
(handle-fill (build PartialFill))
(expect {:px 10 :size 33 :time 100} (first @fills))
(DateTimeUtils/setCurrentMillisSystem))
While the above code does result in a passing test, it would cause unexpected issues if expect ever failed. In expectations a failure throws an exception (to terminate scenario execution) and the time reset would never occur. Even if that wasn't the case, the time related code takes away from the actual focus of the test.
Therefore, expectations has been modified to take a :freeze-time parameter as part of a scenario definition. The :freeze-time parameter can be a string or a boolean - when specifying a string, anything parse-able by Joda will do; if you specify a boolean time will simply be stopped at the moment of execution.
With :freeze-time available we can rewrite the above test in the following way:
(scenario
:freeze-time "2012-4-30"
(handle-fill (build PartialFill))
(expect {:px 10 :size 33 :time 1335758400000} (first @fills)))
The resulting code is easier to work with, while still allowing verification of time.
I believe the domain related code does a better job of demonstrating the point; however, the following examples are available if you'd like something simplified.
(scenario :freeze-time true (expect (DateTime.) (do (Thread/sleep 10) (DateTime.)))) (scenario :freeze-time "2012-4-30TZ" (expect (.getMillis (DateTime.)) 1335744000000))
Tuesday, June 23, 2009
Freezing Joda Time
Once upon a time Mark Needham wrote about freezing Joda Time. Mark gives all the important details for freezing time (which is often helpful for testing), but I came up with some additional code that I like to add on top of his example.
Two things bother me about Mark's example. First of all, I always like the last line of my test to be the assertion. It's not a law, but it is a guideline I like to follow. Secondly, I don't like having to remember that I need to reset the time back to following the system clock.
I came up with the following idea. It's definitely a poor man's closure, but it does the job for me.
The Freeze class is very simple:
The Snippet class is even more simple:
Using this code I can keep my assertions as close to the end of the test method as possible, and it's not possible to forget to reset the time back to the system clock.
Two things bother me about Mark's example. First of all, I always like the last line of my test to be the assertion. It's not a law, but it is a guideline I like to follow. Secondly, I don't like having to remember that I need to reset the time back to following the system clock.
I came up with the following idea. It's definitely a poor man's closure, but it does the job for me.
@Test
public void shouldFreezeTime() {
Freeze.timeAt("2008-09-04").thawAfter(new Snippet() {{
assertEquals(new DateTime(2008, 9, 4, 1, 0, 0, 0), new DateTime());
}});
}
The Freeze class is very simple:
public class Freeze {
public static Freeze timeAt(String dateTimeString) {
DateTimeUtils.setCurrentMillisFixed(JodaDateTime.create(dateTimeString).getMillis());
return new Freeze();
}
public void thawAfter(Snippet snippet) {
DateTimeUtils.setCurrentMillisSystem();
}
}
The Snippet class is even more simple:
public class Snippet {}
Using this code I can keep my assertions as close to the end of the test method as possible, and it's not possible to forget to reset the time back to the system clock.
Subscribe to:
Posts (Atom)