I have a Util class with 1 method which calculates age using joda-time:
public static int getAge(LocalDate birthdate) {
LocalDate today = new LocalDate();
Period period = new Period(birthdate, today, PeriodType.yearMonthDay());
return period.getYears();
}
I've written an extensive JUnit test class but how do I make it time-independent? If I create a test case to calculate someone's age if they were born today in 1970 then the result would be 46 years old. But 1 year from now if i run the test case it would fail because the result would be 47.
So how do I make these test cases time-independent. I was thinking of having some sort of calendar interface that the test cases would create a date object from. I also stumbled across this post which is another possible solution to this but I'm not really sure how to go about it.
A common practice (described in the book Growing Object Oriented Software guided by Tests) is to delegate the responsability of creating the date instance to a collaborator.
Imagine you have a class like this:
public class Clock {
public LocaleDate now(){
return new LocalDate();
}
}
then your code could become
public static int getAge(LocalDate birthdate, Clock clock) {
LocalDate today = clock.now();
Period period = new Period(birthdate, today, PeriodType.yearMonthDay());
return period.getYears();
}
I would be fine not testing Clock#now
as it is trivially correct, but I can now pass in a mocked clock instance to test the getAge
method.
Now this means a class using the static getAge
must provide a clock, the clock would be a dependency for this class. Such dependencies can be injected in various mockable ways.
I personnally am of the injection by constructor
school, but anything from injection by reflection
to proctected factory method (which can therefore be overloaded in an anonymous subclass used to create a test instance) works.
This problem and the design I suggest are discussed at length in the book, in many blog posts and in stack overflow (it looks like java 8 has direct support for it if you are willing to move to java.time)
Use fixed date :
LocalDate today = new LocalDate(2016, 1, 5);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With