Time dependent unit tests

47,340

Solution 1

Joda time supports setting a "fake" current time through the setCurrentMillisFixed and setCurrentMillisOffset methods of the DateTimeUtils class.

See https://www.joda.org/joda-time/apidocs/org/joda/time/DateTimeUtils.html

Solution 2

The best way (IMO) of making your code testable is to extract the dependency of "what's the current time" into its own interface, with an implementation which uses the current system time (used normally) and an implementation which lets you set the time, advance it as you want etc.

I've used this approach in various situations, and it's worked well. It's easy to set up - just create an interface (e.g. Clock) which has a single method to give you the current instant in whatever format you want (e.g. using Joda Time, or possibly a Date).

Solution 3

Java 8 introduced the abstract class java.time.Clock which allows you to have an alternative implementation for testing. This is exactly what Jon suggested in his answer back then.

Solution 4

To add to Jon Skeet's answer, Joda Time already contains a current time interface: DateTimeUtils.MillisProvider

For example:

import org.joda.time.DateTime;
import org.joda.time.DateTimeUtils.MillisProvider;

public class Check {
    private final MillisProvider millisProvider;
    private final DateTime someDate;

    public Check(MillisProvider millisProvider, DateTime someDate) {
        this.millisProvider = millisProvider;
        this.someDate = someDate;
    }

    public boolean isAvailable() {
        long now = millisProvider.getMillis();
        return (someDate.isBefore(now));
    }
}

Mock the time in a unit test (using Mockito but you could implement your own class MillisProviderMock):

DateTime fakeNow = new DateTime(2016, DateTimeConstants.MARCH, 28, 9, 10);
MillisProvider mockMillisProvider = mock(MillisProvider.class);
when(mockMillisProvider.getMillis()).thenReturn(fakeNow.getMillis());

Check check = new Check(mockMillisProvider, someDate);

Use the current time in production (DateTimeUtils.SYSTEM_MILLIS_PROVIDER was added to Joda Time in 2.9.3):

Check check = new Check(DateTimeUtils.SYSTEM_MILLIS_PROVIDER, someDate);

Solution 5

I use an approach similar to Jon's, but instead of creating a specialized interface just for the current time (say, Clock), I usually create a special testing interface (say, MockupFactory). I put there all the methods that I need to test the code. For example, in one of my projects I have four methods there:

  • one that returns a mock-up database client;
  • one that creates a mock-up notifier object that notifies the code about changes in the database;
  • one that creates a mock-up java.util.Timer that runs the tasks when I want it to;
  • one that returns the current time.

The class being tested has a constructor that accepts this interface among other arguments. The one without this argument just creates a default instance of this interface that works "in real life". Both the interface and the constructor are package private, so the testing API doesn't leak outside of the package.

If I need more imitated objects, I just add a method to that interface and implement it in both testing and real implementations.

This way I design code suitable for testing in the first place without imposing too much on the code itself. In fact, the code becomes even cleaner this way since much factory code is gathered in one place. For example, if I need to switch to another database client implementation in real code, I only have to modify just one line instead of searching around for references to the constructor.

Of course, just as in the case with Jon's approach, it won't work with 3rd party code that you are unable or not allowed to modify.

Share:
47,340

Related videos on Youtube

pojo
Author by

pojo

Updated on July 05, 2022

Comments

  • pojo
    pojo almost 2 years

    I need to test a function that whose result will depend on current time (using Joda time's isBeforeNow(), it so happens).

    public boolean isAvailable() {
        return (this.someDate.isBeforeNow());
    }
    

    Is it possible to stub/mock out the system time with (using Mockito, for example) so that I can reliably test the function?

    • DariusL
      DariusL over 8 years
      For some functions the simplest solution is to pass the current time as a parameter.
    • DariusL
      DariusL over 8 years
      Just like with mocking, it doesn't have to be the actual current time. You can hardcode a safe time instant.
  • Laurent Pireyn
    Laurent Pireyn about 13 years
    Joda time has builtin support for that abstraction (see my answer), so you don't have to introduce it in your code.
  • Jon Skeet
    Jon Skeet about 13 years
    @Laurent: I don't think that's actually nearly as elegant. Fundamentally I think a service such as "getting the current time" is a dependency (just as I view random number generation as a dependency) so I think it's good to make that explicit. This means you can parallelize tests, etc too.
  • Laurent Pireyn
    Laurent Pireyn about 13 years
    Point taken. Don't get me wrong: I'm usually in favor of abstraction. However, the notion of current time can be difficult to abstract in a real-life project, especially when third-party libraries are used that don't abstract this notion.
  • Jon Skeet
    Jon Skeet about 13 years
    @Laurent: Oh yes, when you're using third-party libraries it's tricky... but then you'd have the same problem with setCurrentMillisFixed unless your third party library happened to use Joda Time :(
  • Hans-Peter Störr
    Hans-Peter Störr about 12 years
    But these are static methods - you will introduce dependencies between the unittests that way. Thus, I'd prefer Jon Skeets solution.
  • Jon Skeet
    Jon Skeet over 11 years
    @Rogerio: I think we'll have to agree to disagree. I view making the dependency explicit as a wholly good thing, allowing parallelization of testing, and more comprehensive testing of everything time-related.
  • Jon Skeet
    Jon Skeet over 11 years
    @Rogerio: Having looked at your profile, you'd presumably suggest using JMockit to test the static method. Personally I regard that as a sticking-plaster over the failure to specify a dependency (a source of the current time). I'd rather fix the design issue by making the dependency explicit rather than working round it with a particular testing framework.
  • Rogério
    Rogério over 11 years
    @Jon: No, I wouldn't, since Joda Time already provides ways to control the time for testing purposes, as pointed out in other answers/comments. I disagree there is a design issue in this case, though: many dependencies are inherently private and should not be exposed in the public interface of the class, as doing so violates the principle of information hiding while tending to make code more complex than is called for.
  • Jon Skeet
    Jon Skeet over 11 years
    @Rogerio: And as has been pointed out elsewhere, that's still got all the problems of changing a static data source. I don't see that "I depend on the current time" ought to be a "private" dependency. And heck, not all constructors need to be public... As I said before, I suspect we'll have to agree to disagree - but I've used the Clock interface approach many times and always found it to leave my code feeling cleaner and more explicit.
  • Rogério
    Rogério over 11 years
    @Jon: Information hiding, one of the most fundamental software design principles, is all about hiding the "secrets" of a module from its clients, when said clients have no good reason to know them. Reading the current time usually is such a secret, just like sending an email, accessing a database, etc. In most cases, a client module A has no business knowing about the internal dependencies of another module B. Therefore, such details should remain hidden inside B's implementation. This, of course, does not preclude the ability to externally configure those dependencies, or to write unit tests.
  • Jon Skeet
    Jon Skeet over 11 years
    @Rogerio: Normally in Guice I have a public module which is then responsible for providing the relevant services. So that can use a package-private constructor, which is still easy to test, and still makes the dependencies clear. No information hiding problems there, IMO.
  • Rogério
    Rogério over 11 years
    hstoerr: I don't see how there would be dependencies between tests, unless they were to be executed in different threads (which is probably not the case here). But even then, Joda Time provides the DateTimeUtils.setCurrentMillisProvider(DateTimeUtils.MillisP‌​rovider) method, which would certainly allow a thread-bound implementation.
  • Rogério
    Rogério over 11 years
    @Jon: Yes, it wouldn't be necessary to expose the Clock interface in the public interface of whatever class happens to use it internally. Doing so would not expose the dependency on current system time to client classes, but it would still unnecessarily expose it to some separate entity such as the DI container, and (more importantly) it would add extra complexity to the system. It's this extra complexity which I object to. To me, any additional abstraction adds cost which should be justified through real benefits.
  • Jon Skeet
    Jon Skeet over 11 years
    @Rogerio: That's the thing: I think of it as inherent complexity, which is merely being made explicit. I suspect that if it were always provided as a dependency rather than as a static method, you wouldn't be suggesting creating a static method instead, and that you'd actually consider that ugly. But as I've said several times, I think we're going to have to agree to disagree - feel free to reply if you wish, but I'm not going to add any more comments to this already-long thread.
  • Dathan
    Dathan over 10 years
    This sounds like you're going to create a new interface to encapsulate the dependencies of each class under test? Which will then require at least one implementation. So now for every class under test you have the class, at least one test class, the dependency grouping interface, and an implementation of that interface? I really don't like that. And I feel like adding that additional level of indirection between your code and its actual dependencies (i.e., after looking at your class I have to then look at the dependency interface as well) actually makes the code harder to understand.
  • Sergei Tachenov
    Sergei Tachenov over 10 years
    @Dathan, no, not each class. Only those that have dependencies that has to be emulated during testing. In my application there happen to be just one such class. Also, the number of classes doesn't mean anything. If the implementation is just class DefaultMockupFactory implements MockupFactory {Timer createTimer() {return new Timer();}} it isn't that much of a complexity, is it? And having factory.createTimer() somewhere in the code doesn't make the code harder to understand either. But I agree that in some cases it may not be the best way to do it.
  • Dathan
    Dathan over 10 years
    No, I don't think that it adds too much complexity -- just unnecessary complexity. I feel like the additional level of indirection injected by having this facade interface may inhibit the readability of the code. For instance, if I had your code sample, but MockupFactory had a few other methods on it, and I wanted to find all the places in the code where createTimer() was used, I have to navigate from the class under test to the interface, and THEN search for uses of the method instead of just searching in the class.
  • Sergei Tachenov
    Sergei Tachenov over 10 years
    @Dathan, the interface is nested (with package-private visibility) so it's all still inside the class. And anyway, the difference between my and Jon's approach is that I use a single interface (MockupFactory) for all dependencies that have to be emulated, while Jon proposes to have a separate interface for each dependency (TimerFactory and so on). How would you test the code without any interface at all is a mystery to me. One way or another, the additional complexity is needed.
  • Dathan
    Dathan over 10 years
    I agree, some interface needs to be added. But I'd much rather follow interface segregation -- so in this case, I'd strongly prefer Jon's approach. Part of this is that many interfaces are reused around the system -- it's likely that TimerFactory will be reused, and therefore you can wire it up in a DI container once and have the same one used everywhere, while a MockupFactory for a particular class is unlikely to be used more places -- that means more configuration required compared to well-segregated interfaces.
  • Sergei Tachenov
    Sergei Tachenov over 10 years
    @Dathan, oh, now I see the point. In my case, there was only one class that required any kind of special dependency for testing, so it was obviously much better to hide the interface inside the class. If there is more than one class, I'd probably follow Jon's approach too.
  • xli
    xli almost 9 years
    @Jon: I totally agree with you. Now Java 8 has the abstract class Clock.
  • Thomas Eizinger
    Thomas Eizinger about 8 years
    Retrieving the current time from the system is a sideeffect which means that any function doing this is no longer pure. Pure functions on the other hand are very easy to test, as they are completely determinstic. The only way I can think of to come around this, is by moving the sideeffect as far away as possible which results in the solution Jon has proposed. github.com/Frege/frege, a haskell implementation for the JVM, covers this nicely by introducing IO types which state that a given function may produce a sideeffect.
  • jub0bs
    jub0bs about 7 years
    If all you need is the ability to ask "What's the current time?", you don't need a whole clock; you might prefer using a Supplier of the time unit of interest (e.g. LocalDateTime) instead.
  • deamon
    deamon over 6 years
    @Jubobs You can't control the current time returned by LocalDateTime.now() without a Clock passed as a paraemter to now().
  • jub0bs
    jub0bs over 6 years
    @deamon What I'm suggesting is to have a port of type Supplier<LocalDateTime>, in which you can plug in either a real adapter—e.g. LocalDateTime::now—or a fake adapter—e.g. () -> LocalDateTime.of(2017, 10, 24, 0, 0)—where convenient (unit tests). No need for a whole Clock.

Related