See also: Live Testing · Building
Unit tests should be testable without mocking libraries where possible. A fake is a simple replacement that returns canned responses; a mock uses a library like Mockito to intercept real calls.
// Prefer a fake over a Mockito mock when the fake is simple to write
public class FakeConfigurationService implements ConfigurationService {
public Configuration readConfiguration(String configurationName) {
Configuration config = new Configuration();
config.setOwner("foo");
return config;
}
}Good candidates for mocks (rather than fakes):
- Network-connected dependencies (HTTP, database)
- File-system operations
- Third-party libraries with file/network I/O
- Time-dependent operations (mock a
Clock)
Avoid libraries like PowerMock — they interfere with classloaders and JaCoCo coverage.
Instead, wrap the static call in an instance method you can mock:
// Before (not testable)
public String methodToTest() {
return process(Util.notTestFriendlyStaticMethod());
}
// After (testable via injection)
public class ClassToTest {
private final UtilWrapper utilWrapper;
public ClassToTest(UtilWrapper utilWrapper) {
this.utilWrapper = utilWrapper;
}
public String methodToTest() {
return process(utilWrapper.callStaticUtilMethod());
}
}Most Azure SDK client classes are final. To mock them with Mockito 2+:
- Create
src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker - Add a single line to that file:
mock-maker-inline
// Product code
public class TelemetryEvents {
private final EventHubConsumerAsyncClient consumerClient;
public TelemetryEvents(EventHubConsumerAsyncClient consumerClient) {
this.consumerClient = consumerClient;
}
public Flux<TelemetryEvent> getEvents() {
return consumerClient.receiveFromPartition("1", EventPosition.latest())
.map(event -> new TelemetryEvent(event));
}
}// Test code
import reactor.test.publisher.TestPublisher;
import reactor.test.StepVerifier;
import static org.mockito.Mockito.*;
public class TelemetryEventsTest {
@Test
public void canGetEvents() {
EventHubConsumerAsyncClient consumerClient = mock(EventHubConsumerAsyncClient.class);
TestPublisher<EventData> eventsPublisher = TestPublisher.createCold();
eventsPublisher.emit(new EventData("Foo"), new EventData("Bar"));
when(consumerClient.receiveFromPartition(eq("1"), eq(EventPosition.latest())))
.thenReturn(eventsPublisher.flux());
TelemetryEvents telemetryEvents = new TelemetryEvents(consumerClient);
StepVerifier.create(telemetryEvents.getEvents())
.assertNext(event -> isMatchingTelemetry(event))
.assertNext(event -> isMatchingTelemetry(event))
.verifyComplete();
}
}JUnit 5 runs tests in parallel by default to reduce execution time. Several standard dependencies have non-thread-safe global state — understand the gotchas below.
Problem: Mutates a global timeout; can cause other parallel tests to fail with AssertionError.
Fix: Use .verify(Duration) instead of the global timeout:
// Instead of:
StepVerifier.create(flux).verifyComplete(); // may wait forever
// Use:
StepVerifier.create(flux).expectComplete().verify(Duration.ofSeconds(30));The default overload uses a shared global VirtualTimeScheduler. When tests run in parallel this can lead to races.
Fix (choose one):
- Use the overload that accepts a
Supplier<VirtualTimeScheduler>anddispose()the scheduler after the test. - Annotate the test class with
@Isolatedand@Execution(ExecutionMode.SAME_THREAD). - Annotate the specific test method with
@Execution(ExecutionMode.SAME_THREAD).
These mutate global state in Hooks. If other parallel tests drop elements, your test may fail.
Use @Isolated + @Execution(ExecutionMode.SAME_THREAD) when you need these validators.
// Make entire test class sequential and isolated from other parallel tests
@Isolated
@Execution(ExecutionMode.SAME_THREAD)
public class MyTest { ... }Run a specific test class:
mvn -f sdk/<service>/pom.xml test -Dtest=MyTestClassRun a specific test method:
mvn -f sdk/<service>/pom.xml test -Dtest=MyTestClass#myTestMethodAttach a debugger (halts on port 5005):
mvn -f sdk/<service>/pom.xml test -Dtest=MyTestClass#myTestMethod -Dmaven.surefire.debugPowerShell: Quote the flag:
"-Dmaven.surefire.debug"
Re-run without recompiling (use surefire:test instead of test):
mvn -f sdk/<service>/pom.xml surefire:test -Dtest=MyTestClass -Dmaven.surefire.debugThen connect a remote debugger in IntelliJ to localhost:5005.