DurianGlobals: Easy-to-test singletons
Usage
Provides an easy way to initialize a singleton exactly once:
public class Singleton {
public static Singleton instance() {
return Globals.getOrSetTo(Singleton.class, Singleton::new);
}
protected Singleton() {}
...
}
In a testing environment, you can wipe the globals to get a clean state or to replace the standard implementation with a testing one.
public class SingletonTest {
static class SingletonDev extends Singleton {
...
}
@Test
public void someTest() {
try (AutoCloseable wipeGlobals = GlobalsDev.wipe()) {
SingletonDev dev = new SingletonDev();
GlobalsDev.install(Singleton.class, dev);
...
}
}
}
The "trick" is that GlobalsDev
is shipped in a different artifact than the rest, so you can be sure that your Globals
can only be changed in tests, and never in production code:
dependencies {
implementation 'com.diffplug.durian-globals:durian-globals:1.0.0'
testImplementation 'com.diffplug.durian-globals:durian-globals.dev:1.0.0'
}
Built-ins
There are some globals that people frequently want control over during testing.
Time
You can use public static long Time.now()
as a replacement for System.currentTimeMillis()
. And in a test, you can replace it with TimeDev
.
@Test
public void someTimeDependentTest() {
try (AutoCloseable wipeGlobals = GlobalsDev.wipe()) {
TimeDev time = TimeDev.install();
time.setUTC(LocalDate.parse("2019-03-30"));
... // exercise code that uses `Time.now()`
}
}
Requirements
DurianGlobals requires nothing but Java 8+.
In the wild
- Integration testing the spotless-changelog gradle plugin