Failure notification setup in JUnit - Build an Automation Script
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.TestWatcher; import org.junit.jupiter.api.extension.ExtensionContext; import static org.mockito.Mockito.*; import java.util.Optional; class NotificationService { void sendFailureNotification(String testName, String reason) { // Imagine this sends an email or logs the failure } } class FailureNotificationWatcher implements TestWatcher { private final NotificationService notificationService; FailureNotificationWatcher(NotificationService notificationService) { this.notificationService = notificationService; } @Override public void testFailed(ExtensionContext context, Throwable cause) { String testName = context.getDisplayName(); String reason = cause.getMessage(); notificationService.sendFailureNotification(testName, reason); } @Override public void testSuccessful(ExtensionContext context) { // No notification on success } } @ExtendWith(FailureNotificationWatcher.class) public class FailureNotificationTest { static NotificationService notificationService = mock(NotificationService.class); static FailureNotificationWatcher watcher = new FailureNotificationWatcher(notificationService); @Test void passingTest() { // This test passes assert(true); } @Test void failingTest() { // This test fails throw new RuntimeException("Simulated failure"); } @Test void verifyNotificationSent() { // Run the failing test manually to trigger notification ExtensionContext context = mock(ExtensionContext.class); when(context.getDisplayName()).thenReturn("failingTest()"); RuntimeException failure = new RuntimeException("Simulated failure"); watcher.testFailed(context, failure); verify(notificationService, times(1)).sendFailureNotification("failingTest()", "Simulated failure"); } }
The NotificationService class simulates sending failure notifications.
The FailureNotificationWatcher implements JUnit 5's TestWatcher interface to listen for test failures. When a test fails, it calls sendFailureNotification with the test name and failure reason.
The test class FailureNotificationTest uses Mockito to mock NotificationService. It defines a passing test and a failing test. The verifyNotificationSent test manually triggers the failure notification and verifies that the notification method was called exactly once with the correct parameters.
This setup ensures that failure notifications are sent only on test failures and contain the right information.
Now add data-driven testing with 3 different failing scenarios and verify notifications for each
Practice
Solution
Step 1: Understand failure notification purpose
Failure notification is designed to alert developers right when a test fails so they can act quickly.Step 2: Eliminate unrelated options
Speeding tests, auto-fixing, or skipping tests are not related to failure notifications.Final Answer:
To get alerts immediately when a test fails -> Option AQuick Check:
Failure notification = Immediate alerts [OK]
- Thinking it speeds up tests
- Assuming it fixes tests automatically
- Believing it skips tests
Solution
Step 1: Identify JUnit classes for failure detection
TestWatcher is a JUnit rule designed to watch test execution and detect failures.Step 2: Compare with other options
TestRule is a general interface, TestSuite groups tests, TestRunner runs tests but does not notify failures.Final Answer:
TestWatcher -> Option CQuick Check:
Failure detection = TestWatcher [OK]
- Confusing TestRule interface with TestWatcher
- Thinking TestSuite handles failure notifications
- Assuming TestRunner sends alerts
public class MyTest {
@Rule
public TestWatcher watcher = new TestWatcher() {
@Override
protected void failed(Throwable e, Description d) {
System.out.println("Test failed: " + d.getMethodName());
}
};
@Test
public void testFail() {
assertEquals(1, 2);
}
}Solution
Step 1: Understand TestWatcher failed() method
The failed() method runs when a test fails and prints the method name.Step 2: Analyze the testFail() method
assertEquals(1, 2) fails, triggering failed() to print the message.Final Answer:
Prints 'Test failed: testFail' to the console -> Option DQuick Check:
Failed test triggers failed() print [OK]
- Thinking test passes silently
- Expecting automatic email without code
- Assuming runtime exception stops all tests
public class NotifyTest {
@Rule
public TestWatcher watcher = new TestWatcher() {
@Override
protected void failed() {
System.out.println("Failure detected");
}
};
@Test
public void testExample() {
fail();
}
}Solution
Step 1: Check failed() method signature
TestWatcher.failed() requires parameters (Throwable, Description) to override correctly.Step 2: Verify other parts
@Rule is correctly placed, fail() is a JUnit method, TestWatcher works with @Rule.Final Answer:
Missing parameters in failed() method override -> Option AQuick Check:
Override failed() with correct parameters [OK]
- Omitting parameters in failed() override
- Misplacing @Rule annotation
- Confusing fail() method usage
public class EmailAlertTest {
@Rule
public TestWatcher watcher = new TestWatcher() {
@Override
protected void failed(Throwable e, Description d) {
// What should go here?
}
};
@Test
public void testEmail() {
assertTrue(false);
}
}Solution
Step 1: Understand TestWatcher failed() role
failed() runs on test failure; it is the right place to trigger email sending.Step 2: Choose correct action inside failed()
Calling a method to send email with failure details is correct; throwing exceptions or relying on @After is incorrect.Final Answer:
Call a method to send email inside failed(), passing e and d -> Option BQuick Check:
Send email in failed() method [OK]
- Throwing exceptions to send email
- Using @After for failure alerts
- Assuming email sends automatically without code
Ready to prove it?
Pass the test and this pattern moves unknown
