Automate test reporting using JUnit TestWatcher
Preconditions (2)
✅ Expected Result: The console shows messages indicating each test method's name and whether it passed, failed, or was skipped
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestWatcher; import java.util.Optional; class ReportingTestWatcher implements TestWatcher { @Override public void testSuccessful(ExtensionContext context) { String testName = context.getDisplayName(); System.out.println("[PASS] Test succeeded: " + testName); } @Override public void testFailed(ExtensionContext context, Throwable cause) { String testName = context.getDisplayName(); System.out.println("[FAIL] Test failed: " + testName + ". Reason: " + cause.getMessage()); } @Override public void testDisabled(ExtensionContext context, Optional<String> reason) { String testName = context.getDisplayName(); System.out.println("[SKIP] Test disabled: " + testName + ". Reason: " + reason.orElse("No reason provided")); } } @ExtendWith(ReportingTestWatcher.class) public class SampleTests { @Test void testSuccess() { // This test will pass int sum = 2 + 3; assert sum == 5; } @Test void testFailure() { // This test will fail int product = 2 * 2; assert product == 5 : "Product should be 5"; } @Test void testAnotherSuccess() { // Another passing test String text = "hello".toUpperCase(); assert text.equals("HELLO"); } @Test @org.junit.jupiter.api.Disabled("Not implemented yet") void testDisabled() { // This test is disabled } }
The ReportingTestWatcher class implements JUnit 5's TestWatcher interface to listen to test lifecycle events.
We override testSuccessful, testFailed, and testDisabled methods to print messages to the console with the test name and status.
The SampleTests class uses @ExtendWith to attach the watcher. It contains tests that pass, fail, and one disabled test to demonstrate all cases.
When running the tests, the console will show clear messages indicating which tests passed, failed, or were skipped, helping with reporting.
Extend the TestWatcher to write the test results to a file instead of console output.
TestWatcher in JUnit tests?TestWatcher is a JUnit class designed to listen to test lifecycle events such as when a test starts, succeeds, fails, or finishes.TestWatcher.TestWatcher method that runs when a test fails?failed method in TestWatcher is public void failed(ExtensionContext context, Throwable cause).ExtensionContext first, then Throwable.TestWatcher subclass, what will be printed if the test exampleTest fails?class MyWatcher extends TestWatcher {
@Override
public void failed(ExtensionContext context, Throwable cause) {
context.getTestMethod().ifPresent(method -> System.out.println(method.getName() + " failed"));
}
}
@Test
@ExtendWith(MyWatcher.class)
void exampleTest() {
assertEquals(1, 2);
}failed method prints the test method name plus " failed".exampleTest, so the output will be "exampleTest failed".TestWatcher subclass that aims to log test success:class SuccessWatcher extends TestWatcher {
@Override
public void succeeded(Description description) {
System.out.println(description.getDisplayName() + " succeeded");
}
}TestWatcher methods use ExtensionContext parameter, not Description.public void succeeded(ExtensionContext context) in JUnit 5.TestWatcher that logs test start and failure events, but only for tests whose names start with "critical". Which approach correctly implements this behavior in JUnit 5?TestWatcher methods to override are starting(ExtensionContext) and failed(ExtensionContext, Throwable).context.getDisplayName() to get the test name and check if it starts with "critical" before logging.starting(ExtensionContext context) and failed(ExtensionContext context, Throwable cause), check context.getDisplayName() starts with "critical" before logging [OK]Pass the test and this pattern moves unknown