Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Time-independent JUnit Test Cases

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.

like image 569
Richard Avatar asked Mar 13 '23 16:03

Richard


2 Answers

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)

like image 107
Jean Avatar answered Mar 16 '23 07:03

Jean


Use fixed date :

    LocalDate today = new LocalDate(2016, 1, 5);
like image 31
Mrinal Avatar answered Mar 16 '23 06:03

Mrinal