The intersection of technology and leadership

Controlling Time

Disclaimer: This technique does not work outside of programming. Do not try this on your neighbours, kids or pets…

What’s wrong with time dependent tests?
It’s easy to write tests that are far too flaky and intermittent. Worse yet, a quick fix often results in putting a pause to tests that make them drag out longer and longer. Alternatively, unneeded complexity is added to try to do smart things to poll for tests to time out.

What can we do about it?
I’m all about solutions, so I’m out about to outline the secret to controlling time (in at least unit tests). Here’s a situation you might recognise. Or not. Sorry to anyone vegetarian reading this entry.

We have a class called Beef that knows when it’s past its prime using the Joda Time libraries.

package com.thekua.examples;

import org.joda.time.DateTime;

public class Beef {
	private final DateTime expiryDate;

	public Beef(DateTime expiryDate) {
		this.expiryDate = expiryDate;
	}
	
	public boolean isPastItsPrime() {
		DateTime now = new DateTime(); // Notice this line?
		return now.isAfter(expiryDate); 
	}
}

Surprise, surprise. We also have a unit test for it:

package com.thekua.examples;

import static org.junit.Assert.assertTrue;
import org.joda.time.DateTime;
import org.junit.Test;

public class BeefTest {
	@Test
	public void shouldBePastItsPrimeWhenExpiryDateIsPast() throws Exception {
		int timeToPassForExpiry = 100;
		
		Beef beef = new Beef(new DateTime().plus(timeToPassForExpiry));
		
		Thread.sleep(timeToPassForExpiry * 2); // Sleep? Bleh...
		
		assertTrue(beef.isPastItsPrime());
	}
}

Step 1: Contain time (in an object of course)
The first step is to contain all the use of time concepts behind an object. Don’t even try to call this class a TimeProvider. It’s a Clock okay? (I’m sure I used to call it that in the past as well, so don’t worry!). The responsibility of the Clock is to tell us the time. Here’s what it looks like:

package com.thekua.examples;

import org.joda.time.DateTime;

public interface Clock {
	DateTime now();
}

In order to support the system working as normally, we are going to introduce the SystemClock. I sometimes call this a RealClock. It looks a bit like this:

package com.thekua.examples;

import org.joda.time.DateTime;

public class SystemClock implements Clock {
	public DateTime now() {
		return new DateTime();
	}
}

We are now going to let our Beef now depend on our Clock concept. It should now look like this:

package com.thekua.examples;

import org.joda.time.DateTime;

public class Beef {
	private final DateTime expiryDate;
	private final Clock clock;

	public Beef(DateTime expiryDate, Clock clock) {
		this.expiryDate = expiryDate;
		this.clock = clock;
	}
	
	public boolean isPastItsPrime() {
		DateTime now = clock.now();
		return now.isAfter(expiryDate); 
	}
}

If you wanted to, the step by step refactoring would look like:

  1. Replace new DateTime() with new SystemClock().now()
  2. Replace new instance with field
  3. Instantiate new field in constructor

We’d use the RealClock in both the code that creates the Beef as well as our test. Our test should look like…

package com.thekua.examples;

import static org.junit.Assert.assertTrue;
import org.junit.Test;

public class BeefTest {
	@Test
	public void shouldBePastItsPrimeWhenExpiryDateIsPast() throws Exception {
		int timeToPassForExpiry = 100;
		SystemClock clock = new SystemClock();
		
		Beef beef = new Beef(clock.now().plus(timeToPassForExpiry), clock);
		
		Thread.sleep(timeToPassForExpiry * 2);
		
		assertTrue(beef.isPastItsPrime());
	}
}

Step 2: Change the flow of time in tests
Now that we have the production code dependent on an abstract notion of time, and our test still working, we now want to substitute the RealClock with another object that allows us to shift time for tests. I’m going to call it the ControlledClock. Its responsibility is to control the flow of time. For the purposes of this example, we’re only going to allow time to flow forward (and ensure tests use relative times instead of absolute). You might vary it if you needed very precise dates and times. Note the new method forwardTimeInMillis.

package com.thekua.examples;

import org.joda.time.DateTime;

public class ControlledClock implements Clock {
	private DateTime now = new DateTime();

	public DateTime now() {
		return now;
	}	
	
	public void forwardTimeInMillis(long milliseconds) {
		now = now.plus(milliseconds);
	}
}

Now we can use this new concept in our tests, and replace the way that we previously forwarded time (with the Thread.sleep) with our new class. Here’s what our final test looks like now:

package com.thekua.examples;

import static org.junit.Assert.assertTrue;
import org.junit.Test;

public class BeefTest {
	@Test
	public void shouldBePastItsPrimeWhenExpiryDateIsPast() throws Exception {
		int timeToPassForExpiry = 100;
		ControlledClock clock = new ControlledClock();
		
		Beef beef = new Beef(clock.now().plus(timeToPassForExpiry), clock);
		
		clock.forwardTimeInMillis(timeToPassForExpiry * 2);
		
		assertTrue(beef.isPastItsPrime());
	}
}

We can even further improve this test to be more specific by forwarding time by simply adding one rather than multiplying twice.

Step 3: Save time (and get some real sleep)
Although this is a pretty trivial example of a single use of time dependent tests, it shouldn’t take too much effort to introduce this concept to any classes that depend on time. Not only will you save yourself heart-ache with either flaky, broken tests, but you should also save yourself the waiting time you’d otherwise need to introduce, leading to faster test execution, and that wonderful thing of fast feedback.

Enjoy! Let me know what you thought of this by leaving a comment.

10 Comments

  1. Nathan McDonald

    For a simpler approach in tests, you can just use:
    org.joda.time.DateTimeUtils#setCurrentMillisFixed(long)

    to set the time you want used by the rest of joda, such as when new DateTime() is called.

    in the tearDown for your test, restore it with:

    org.joda.time.DateTimeUtils#setCurrentMillisSystem()

    This allows the codebase to use new DateTime() whenever the current time is required, without needing to inject some other interface to facilitate controlled testing.

  2. Patrick

    Hi Nathan,

    Thanks for your comment. I didn’t know that this was here as an option. I’m still a little bit uncomfortable using static methods for anything like this, but it could certainly be useful for people as a starting place.

  3. Ville Oikarinen

    Hi Patrick.

    I understand your point about naming: mainstream OO naming is sometimes humorous and clumsy, and more “natural” naming has its merits.

    On the other hand, just like an electronic office shouldn’t just mimic paper office, maybe the language in code could also do better than its real-life counterpart.

    The richness of natural languages is of course a blessing for art and other human activity, but in code certain minimalism and consistency is good.

    If I need any X in my code, it’s easy if I can just see if there is an interface named XProvider to be injected, instead of having to activate my (non-native) English skills and find the correct natural term for the provider.

    Program code isn’t supposed to be read in a poetry competition, after all, it’s supposed to be effective enough to be even boring sometimes 🙂

    – Ville Oikarinen
    comment provider

  4. Patrick

    Hi Ville!

    Thanks for your comment. I can appreciate the need to consider leaving code that needs to cross multiple cultures and languages. I understand that calling something X and XProvider is easy, and may be conventional for many programmers, however I still prefer to name my classes to leave as much intent in them as possible.

    Although I could name a class XProvider, what does that tell future programmers? What other characteristics should it have? If I can’t think of a better name, I prefer to name things DefaultX instead.

    I also believe that finding implementations of X shouldn’t be hard for developers these days with excellent tools like Eclipse and IntelliJ showing us inheritors or class hierarchies with a short keyboard shortcut (or click away). Javadoc, albeit slower, also gives us access to the same information.

    I will admit that not all classes will match real world concepts, but it doesn’t mean that we should be lax on the principle of programming for readability vs programming for convenience.

  5. Ville Oikarinen

    Yes, finding implementations for a given interface is easy, and I also name implementations in a quite similar way: if I don’t have anything special to say about an implementation for X, I’ll call it XDefaultImpl.

    But finding the provider interface isn’t so easy. The best way that pops into my mind is to find references to the interface or even to a constructor of some implementation.

    I agree, readability is at least as important as convenience. But I believe minimal vocabulary can coexist with readability.

    Mathematics is a good example: most laymen find mathematical jargon clumsy and dull (and unreadable), but I believe it’s quite optimal the way it is, after generations of evolution.

    And, many projects “overload” seemingly universal concepts with project-specific semantics anyway (like you said, “not all classes will match real world concepts”). Or, even more likely, they simplify the concepts.

    Take Clock, for example. Does our program need any physical properties of the clock instrument, like dimensions? Is it a digital or an analog clock? Does it have alarm functionality? Does it ring a bell every hour? If not, maybe we don’t need the whole Clock interface, only a little part of it, namely a provider for time.

    Well, I hope I don’t sound too critical. Clock is also a good name, but I just wanted to show that the “classical” naming can also be something else than a learned bad habit.

  6. Ville Oikarinen

    Yes, clock is a good name, not least because unix uses it 🙂

    And you are right, ubiquitous language is the most important point here, and _if_ time/clock is an essential part of the domain, then it’s wise to use the term domain experts find best.

    Otherwise (in most cases?) naming an internal detail like this is more a matter of taste (of the developers involved).

  7. Patrick

    Hi Ville,

    You don’t sound too critical and I do appreciate hearing your point of view. You have lots of good points. Here are some responses…

    You could still argue over the merits of TimeProvider but I still don’t know anyone (outside of programmers) that would call a Clock that. Even *nix people call it the system clock (not a system time provider). You talk about other aspects and depending on what you were modelling, could potentially all be valid. I would say though that all clocks tell the time, yet all clocks do not have all the properties you mention (alarms, dimensions, etc).

    For some programmers, mathematics might be very useful for communicating, but I also believe in the Ubiquitious Language and even then, mathematics is not often the best choice for this.

    I also agree that minimalism can exist with readability.

  8. Andreas

    Interesting. An alternative to control or simulate the time for unit tests, instead of adding code, would be a 3rd party tool to handle the needed time changes. Several exist, I’ve had success with TimeShiftX

  9. Patrick

    You have a good point Andreas as an alternative. I would question how easy it would be to automate outside 3rd party tools from within a unit test. In my experience, external dependencies (e.g. things that are started in another process) often require too much manual intervention or too much effort to automate.

    Thanks for pointing out an alternative

  10. Raymond

    Time Machine is a pretty good software as well. Handles what Time Shift X does but a little more affordable. Both are good tools and are pretty transparent. I’ve never run into issues either.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

© 2024 patkua@work

Theme by Anders NorenUp ↑