Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling unit tests with a condition on the current time

I'm taking a stab at setting up unit tests for some utility classes in a project I'm working on, and one of the classes (contains licensing info) has a method that does some determination based on the current time.

i.e. the license contains an expiry date, and the license string validates that date, but the actual logic to see if the license is expired is based on the current time.

public boolean isValid()
{
    return isLicenseStringValid() && !isExpired();
}

public boolean isExpired()
{
    Date expiry = getExpiryDate();
    if( expiry == null ) {
        return false;
    }

    Date now = new Date();

    return now.after( expiry );
}

So, I'm not sure what to do, since the 'new Date()' thing isn't a static criterion.

  1. Should I not bother to test 'isValid', and just test 'isLicenseStringValid()' and the 'getExpiryDate()' function separately?
  2. Do I just use a license key in the test with a crazy long expiry such that I'll have switched jobs by the time it expires?
  3. Do I try to mock out 'new Date()' to some 'getCurrentTime()' method such that I can fake what time it is now?

What do others normally do with tests that are time-conditional?

like image 826
Shawn D. Avatar asked Aug 11 '10 14:08

Shawn D.


3 Answers

Definitely mock out new Date().

Create a Clock interface with a getCurrentTime() method or something similar. That way you can have a FakeClock for testing and a SystemClock which uses System.currentTimeMillis() or whatever.

I've done this a number of times - it's worked extremely well. It's logical too - effectively you require a "current time service" so that should be injected like any other dependency.

like image 50
Jon Skeet Avatar answered Sep 24 '22 13:09

Jon Skeet


I usually inject a date provider into the tested code. This also helps if you need to switch conventions or otherwise "fix" the time testing code.

like image 36
Mike Burton Avatar answered Sep 21 '22 13:09

Mike Burton


Use dependency injection and inject a TimeProvider that provides a getExpiryDate() method.

like image 31
Mitch Wheat Avatar answered Sep 24 '22 13:09

Mitch Wheat