Testing Utilities
A collection of testing utilities for Java projects, providing fake
concurrency primitives (clocks, executors), console I/O capture, classpath
resource helpers, Kubernetes ConfigMap simulation, and random text generation.
Includes dedicated integration modules for both JUnit 4 and JUnit 5 with
annotation-driven configuration and parameter injection.
See morimekta.net/utils for procedures on releases.
Getting Started
To add to maven: Add this line to pom.xml under dependencies:
<dependencies>
<dependency>
<groupId>net.morimekta.utils</groupId>
<artifactId>testing</artifactId>
<version>5.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.morimekta.utils</groupId>
<artifactId>testing-junit4</artifactId>
<version>5.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.morimekta.utils</groupId>
<artifactId>testing-junit5</artifactId>
<version>5.6.1</version>
<scope>test</scope>
</dependency>
</dependencies>
To add to gradle: Add this line to the dependencies group in build.gradle:
testImplementation 'net.morimekta.utils:testing:5.6.1'
testImplementation 'net.morimekta.utils:testing-junit4:5.6.1'
testImplementation 'net.morimekta.utils:testing-junit5:5.6.1'
Testing
General testing utilities.
Concurrency Utils
FakeClock: A fake implementation ofjava.time.Clockthat holds time constant until explicitly advanced viatick(). Listeners can be registered to be notified when time progresses, making it easy to test time-dependent code deterministically without real delays.
FakeClock clock = FakeClock.forCurrentTimeMillis(1234567890_000L);
clock.addListener(newInstant -> System.out.println("Time: " + newInstant));
clock.tick(Duration.ofSeconds(5));
FakeScheduledExecutor: AScheduledExecutorServicethat uses aFakeClockas its time source and executes tasks in a real background thread pool. Tasks are triggered when the fake clock is ticked, giving you control over when scheduled work runs while still exercising real concurrency.
FakeClock clock = new FakeClock();
FakeScheduledExecutor executor = new FakeScheduledExecutor(clock);
Future<String> future = executor.schedule(() -> "done", 100, MILLISECONDS);
assertThat(future.isDone(), is(false));
clock.tick(100);
Thread.sleep(10); // let background thread complete
assertThat(future.get(), is("done"));
executor.shutdown();
ImmediateExecutor: AnExecutorServicethat runs all submitted tasks synchronously in the calling thread. The task completes beforesubmit()returns, so the returned future is always already done. Useful for removing threading complexity from unit tests.
ImmediateExecutor executor = new ImmediateExecutor();
Future<String> future = executor.submit(() -> "immediate");
assertThat(future.isDone(), is(true));
assertThat(future.get(), is("immediate"));
ImmediateScheduledExecutor: AScheduledExecutorServicethat uses aFakeClockfor scheduling and runs tasks synchronously in the thread that triggers the clock tick. UnlikeFakeScheduledExecutor, no background threads are involved, making tests fully deterministic and single-threaded.
FakeClock clock = new FakeClock();
ImmediateScheduledExecutor executor = new ImmediateScheduledExecutor(clock);
AtomicInteger counter = new AtomicInteger(0);
executor.scheduleAtFixedRate(counter::incrementAndGet, 0, 100, MILLISECONDS);
clock.tick(100);
assertThat(counter.get(), is(1));
clock.tick(200);
assertThat(counter.get(), is(3));
Console Utils
Console: An interface for controlling and inspecting console I/O during testing. Provides access to a fake TTY and captured stdout/stderr content, and allows setting stdin programmatically.
console.setInput("yes\n");
System.out.println("Hello");
assertThat(console.output(), is("Hello\n"));
ConsoleManager: Base class that hijacksSystem.in,System.out, andSystem.errwith fake implementations for the duration of a test. Captured output can be inspected via theConsoleinterface, and the original streams are restored after each test. Supports dumping captured output on test failure for easier debugging.
I/O and File Utils
ResourceUtil: Utility class for loading classpath resources in tests. Can copy a resource to a filesystem path or read its content as a string, using the calling class as the resource loading context.
Path file = ResourceUtil.copyResourceTo("/schema.sql", tempDir);
String content = ResourceUtil.resourceAsString("/test-data.json");
TestConfigMap: Wraps a directory to simulate a Kubernetes ConfigMap volume mount for testing. Manages versioned snapshots with symbolic links and supports atomic updates via a try-with-resources transaction, just like a real ConfigMap mount.
TestConfigMap config = new TestConfigMap(tempDir);
try (var update = config.update()) {
update.copyResource("/default-config.txt");
update.writeContent("custom.txt", "value");
}
assertThat(config.getPath("custom.txt"), exists());
Text Utils
EnglishWords: A lightweight random text generator for producing dummy test data. Generates random English words, sentences, paragraphs, and standard Lorem Ipsum text using a simple subject-verb-object sentence pattern.
String word = EnglishWords.word(); // e.g. "dog"
String sentence = EnglishWords.sentence(50); // at least 50 chars
String para = EnglishWords.paragraph(3); // 3 sentences
String lorem = EnglishWords.loremIpsum();
JUnit 4
Utilities specialized for JUnit 4.
ConsoleWatcher: A JUnit 4TestWatcher@Rulethat sets up a fake console before each test and restores the original system streams afterward. Provides fluent configuration for terminal size, interactivity, and dumping output on test failure.
@Rule
public ConsoleWatcher console = new ConsoleWatcher()
.withTerminalSize(20, 80)
.interactive()
.dumpOnFailure();
@Test
public void testOutput() {
System.out.println("Hello");
assertThat(console.console().output(), containsString("Hello"));
}
DataProviderUtil: Utility forcom.tngtech.java:junit-dataproviderthat generates the Cartesian product of multiple parameter dimensions. Pass in lists of values for each dimension and get back a 2D array of all combinations, simplifying parameterized test setup.
@DataProvider
public static Object[][] testParams() {
return DataProviderUtil.buildDataDimensions(
List.of(ContentType.WALLPAPER, ContentType.AUDIO),
List.of(Locale.US, Locale.DE)
);
// Produces: [WALLPAPER,US], [WALLPAPER,DE], [AUDIO,US], [AUDIO,DE]
}
JUnit 5
Utilities specialized for JUnit 5.
ConsoleExtension: A JUnit 5 extension that provides fake console I/O with parameter injection support. InjectsConsoleorTTYdirectly into test method parameters, and supports annotations like@ConsoleSize,@ConsoleInteractive, and@ConsoleDumpOutputOnFailurefor configuration.
@ExtendWith(ConsoleExtension.class)
@ConsoleSize(rows = 20, cols = 80)
@ConsoleInteractive
public class MyTest {
@Test
public void testOutput(Console console) {
System.out.println("Hello");
assertThat(console.output(), containsString("Hello"));
}
}
ParamsProviderUtil: Utility for JUnit 5@ParameterizedTestwith@MethodSourcethat generates the Cartesian product of parameter dimensions. Transforms multipleArgumentsobjects into aStream<Arguments>of all combinations.
public static Stream<Arguments> params() {
return ParamsProviderUtil.buildArgumentDimensions(
arguments(ContentType.WALLPAPER, ContentType.AUDIO),
arguments(Locale.US, Locale.DE)
);
}
@ParameterizedTest
@MethodSource("params")
public void test(ContentType type, Locale locale) { ... }
DataSourceExtension: A JUnit 5 extension that manages a JDBCDataSourcefor database testing. Creates an in-memory H2 database by default and supports parameter injection ofJdbi,DataSource, or the connection URI string. Use annotations like@DataSourceMode,@DataSourceSchema, and@DataSourceDriverClassto configure the database engine and initial schema.
@ExtendWith(DataSourceExtension.class)
@DataSourceMode(DataSourceMode.Mode.POSTGRESQL)
public class MyDatabaseTest {
@Test
@DataSourceSchema("/schema.sql")
public void testQuery(Jdbi jdbi) {
var db = jdbi.onDemand(MyDBI.class);
assertThat(db.queryUsers(), is(notNullValue()));
}
}
Major Version Changes
4.x->5.x: FakeScheduledExecutor renamed ImmediateScheduledExecutor and new FakeScheduledExecutor created using a real background executor, but using the fake clock to trigger the scheduled tasks.