TestWatcher helps you see what happened during tests. It reports when tests start, succeed, fail, or skip.
TestWatcher for reporting in JUnit
Introduction
Syntax
JUnit
public class MyTestWatcher extends TestWatcher {
@Override
protected void succeeded(Description description) {
// code when test passes
}
@Override
protected void failed(Throwable e, Description description) {
// code when test fails
}
@Override
protected void starting(Description description) {
// code when test starts
}
@Override
protected void finished(Description description) {
// code when test finishes
}
}Override only the methods you need.
Use Description to get test method name and class.
Examples
JUnit
public class MyWatcher extends TestWatcher { @Override protected void succeeded(Description description) { System.out.println(description.getMethodName() + " passed"); } }
JUnit
public class MyWatcher extends TestWatcher { @Override protected void failed(Throwable e, Description description) { System.out.println(description.getMethodName() + " failed: " + e.getMessage()); } }
JUnit
public class MyWatcher extends TestWatcher { @Override protected void starting(Description description) { System.out.println("Starting test: " + description.getMethodName()); } @Override protected void finished(Description description) { System.out.println("Finished test: " + description.getMethodName()); } }
Sample Program
This test class uses TestWatcher to print messages for each test event. One test passes, the other fails.
JUnit
import org.junit.Rule; import static org.junit.Assert.*; import org.junit.Test; import org.junit.rules.TestWatcher; import org.junit.runner.Description; public class SampleTest { @Rule public TestWatcher watcher = new TestWatcher() { @Override protected void starting(Description description) { System.out.println("Starting: " + description.getMethodName()); } @Override protected void succeeded(Description description) { System.out.println("Passed: " + description.getMethodName()); } @Override protected void failed(Throwable e, Description description) { System.out.println("Failed: " + description.getMethodName() + " - " + e.getMessage()); } @Override protected void finished(Description description) { System.out.println("Finished: " + description.getMethodName()); } }; @Test public void testSuccess() { // This test will pass int a = 1 + 1; assertEquals(2, a); } @Test public void testFailure() { // This test will fail int a = 1 + 1; assertEquals(3, a); } }
Important Notes
TestWatcher works with JUnit 4 rules.
Use Description methods like getMethodName() to identify tests.
TestWatcher helps add custom logging without changing test code.
Summary
TestWatcher lets you react to test events like start, success, failure, and finish.
It helps add useful reports and logs during test runs.
Override only the methods you need for simple and clear code.
Practice
1. What is the primary purpose of using
TestWatcher in JUnit tests?easy
Solution
Step 1: Understand TestWatcher role
TestWatcheris a JUnit class designed to listen to test lifecycle events such as when a test starts, succeeds, fails, or finishes.Step 2: Differentiate from other test tasks
Writing assertions, mocking, or configuring databases are separate concerns and not the main purpose ofTestWatcher.Final Answer:
To react to test lifecycle events like start, success, failure, and finish -> Option AQuick Check:
TestWatcher = react to test events [OK]
Hint: TestWatcher listens to test events, not assertions or mocks [OK]
Common Mistakes:
- Confusing TestWatcher with assertion writing
- Thinking TestWatcher creates mocks
- Assuming TestWatcher manages test setup like DB connections
2. Which method signature correctly overrides the
TestWatcher method that runs when a test fails?easy
Solution
Step 1: Recall TestWatcher method signature
Thefailedmethod inTestWatcherispublic void failed(ExtensionContext context, Throwable cause).Step 2: Check method modifiers and parameter order
It must be public, return void, and parameters areExtensionContextfirst, thenThrowable.Final Answer:
public void failed(ExtensionContext context, Throwable cause) -> Option AQuick Check:
failed method = public void failed(ExtensionContext, Throwable) [OK]
Hint: Check parameter order and access modifier for overrides [OK]
Common Mistakes:
- Swapping parameter order
- Using protected instead of public
- Missing return type or wrong method name
3. Given the following
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);
}medium
Solution
Step 1: Understand what failed() prints
The overriddenfailedmethod prints the test method name plus " failed".Step 2: Identify test method name on failure
The test method is namedexampleTest, so the output will be "exampleTest failed".Final Answer:
exampleTest failed -> Option DQuick Check:
Print = methodName + " failed" = exampleTest failed [OK]
Hint: Print uses description.getMethodName() on failure [OK]
Common Mistakes:
- Assuming no output on failure
- Printing only 'failed' without method name
- Confusing method name with test class name
4. Identify the error in this
TestWatcher subclass that aims to log test success:class SuccessWatcher extends TestWatcher {
@Override
public void succeeded(Description description) {
System.out.println(description.getDisplayName() + " succeeded");
}
}medium
Solution
Step 1: Check JUnit version and method signature
In JUnit 5,TestWatchermethods useExtensionContextparameter, notDescription.Step 2: Identify correct succeeded() signature
The correct override ispublic void succeeded(ExtensionContext context)in JUnit 5.Final Answer:
Method signature is incorrect; it should be public void succeeded(ExtensionContext context) -> Option BQuick Check:
JUnit 5 TestWatcher uses ExtensionContext parameter [OK]
Hint: JUnit 5 TestWatcher methods use ExtensionContext, not Description [OK]
Common Mistakes:
- Using JUnit 4 signatures in JUnit 5
- Wrong parameter types or order
- Confusing access modifiers
5. You want to create a custom
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?hard
Solution
Step 1: Identify correct JUnit 5 TestWatcher methods
In JUnit 5,TestWatchermethods to override arestarting(ExtensionContext)andfailed(ExtensionContext, Throwable).Step 2: Filter test names using context.getDisplayName()
Usecontext.getDisplayName()to get the test name and check if it starts with "critical" before logging.Final Answer:
Override starting(ExtensionContext context) and failed(ExtensionContext context, Throwable cause), check context.getDisplayName() starts with "critical" before logging -> Option CQuick Check:
JUnit 5 TestWatcher + ExtensionContext + name check = Overridestarting(ExtensionContext context)andfailed(ExtensionContext context, Throwable cause), checkcontext.getDisplayName()starts with "critical" before logging [OK]
Hint: Use ExtensionContext methods and check displayName for filtering [OK]
Common Mistakes:
- Using JUnit 4 method signatures in JUnit 5
- Checking wrong parameter types
- Using lifecycle methods not related to TestWatcher
Recommended
Ready to prove it?
Pass the test and this pattern moves unknown
10 questions ~5 mineasy hard
