Skip to content

Breaking static dependencies using Java 8 lambdas

Static dependencies are usually bad , because that dependencies are based on the class level and class objects can not be replaced at runtime in contrast to object instances.

That’s why static dependencies are usually a pain if it comes to tests. When you want to write a unit test you usually want to mock the dependent objects, but you can’t do that if the dependent object is a class.

Timing is for example hard to test, because it is based on the static call to System.currentTimeMillis(); and the result of currentTimeMillis changes all the time. Of course it does, because it’s the nature of time but that makes it also hard to test. For tests we need predictable results. So I will pick this example to show you how method references can help.

Assume you wrote the following class.

public class StopWatch {
	private long startMs;

	public void start() {
		this.startMs = System.currentTimeMillis();
	}

	public long getDurationMs() {
		long now = System.currentTimeMillis();
		return now - this.startMs;
	}
}

It’s hard to test that durationMs() will return correct results, isn’t it. How can you write an assertion? It would be good if you could stop the time, but noone can do that or is there a way you can do it? To stop the time you must take control over the return values of currentTimeMillis(). So let’s break that static dependency to make it replaceable.

Maybe you are lucky and you are using Java 8 or above. Then you can replace the static dependency with a method refrerence.

import java.util.Objects;
import java.util.function.Supplier;

public class StopWatch {

	private Supplier<Long> currentTimeSupplier = System::currentTimeMillis;

	private long startMs;

	public StopWatch() {
	}

	/**
	 * Default scoped constructor for testing purposes. If you don't like this
	 * approach you can also set the currentTimeSupplier via reflection and omit
	 * this constructor. Or use some of the tools that testing frameworks provide
	 * like Deencapsulation provided by JMockit.
	 */
	StopWatch(Supplier<Long> currentTimeSupplier) {
		this.currentTimeSupplier = Objects.requireNonNull(currentTimeSupplier);
	}

	public void start() {
		this.startMs = currentTimeSupplier.get();
	}

	public long getDurationMs() {
		long now = currentTimeSupplier.get();
		return now - this.startMs;
	}
}

Now that you can replace the currentTimeSupplier you can easily write reliable unit tests.

public class StopWatchTest {

	@Test
	public void durationMs() {
		Supplier<Long> currentTimeMock = Mockito.mock(Supplier.class);
		StopWatch stopWatch = new StopWatch(currentTimeMock);

		Mockito.when(currentTimeMock.get()).thenReturn(20L);
		stopWatch.start();

		Mockito.when(currentTimeMock.get()).thenReturn(150L);
		long durationMs = stopWatch.getDurationMs();

		Assert.assertEquals(130L, durationMs);
	}
}

You can also use lambdas or method references in a lot of other cases to break static dependencies. E.g. for static field references

// Replace
private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_LOCAL_DATE;
// with
private Supplier<DateTimeFormatter> dateTimeFormatterSupplier = () -> DateTimeFormatter.ISO_LOCAL_DATE;

I hope I could give you some ideas of how to improve your software or how to make it easily testable. Let me know how it works for you. Just comment.

Leave a Reply

Your email address will not be published. Required fields are marked *

 

GDPR Cookie Consent with Real Cookie Banner