package lab.jm; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import java.time.Clock; import java.time.Instant; import java.time.ZoneOffset; import java.util.Map; import lab.jm.fixtures.FlakyFixtures; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Test; /** Q29 and Q30: flaky tests. */ class F_FlakyTest extends Lab { @Test void q29_orderDependenceAndTime() { q(29, "flaky-order-and-time"); FlakyFixtures.SharedState.REGISTRY.clear(); Run forward = Run.of(FlakyFixtures.SharedState.class, Map.of("junit.jupiter.testmethod.order.default", MethodOrderer.MethodName.class.getName())); FlakyFixtures.SharedState.REGISTRY.clear(); Run reverse = Run.of(FlakyFixtures.SharedState.class, Map.of("junit.jupiter.testmethod.order.default", FlakyFixtures.ReverseOrder.class.getName())); p("--- order a_, b_ (alphabetical) ---"); forward.events.forEach(e -> p("%s", e)); p("--- order b_, a_ (reversed) ---"); reverse.events.forEach(e -> p("%s", e)); reverse.failures.forEach(f -> p(" %s: %s", f.getClass().getSimpleName(), f.getMessage())); PaymentGateway gw = mock(PaymentGateway.class); Clock morning = Clock.fixed(Instant.parse("2026-10-26T10:00:00Z"), ZoneOffset.UTC); Clock night = Clock.fixed(Instant.parse("2026-10-26T23:30:00Z"), ZoneOffset.UTC); p("--- time: the same code with an injected Clock ---"); p("acceptsOrders() at 10:00 UTC : %s", new OrderService(gw, morning).acceptsOrders()); p("acceptsOrders() at 23:30 UTC : %s", new OrderService(gw, night).acceptsOrders()); assertTrue(forward.failures.isEmpty()); assertEquals(1, reverse.failures.size()); assertTrue(new OrderService(gw, morning).acceptsOrders()); assertFalse(new OrderService(gw, night).acceptsOrders()); } @Test void q30_repeatedTestFailureThreshold() { q(30, "repeated-test-failure-threshold"); Run run = Run.of(FlakyFixtures.Intermittent.class); run.events.forEach(e -> p("%s", e)); long failed = run.events.stream().filter(e -> e.endsWith("FAILED")).count(); long skipped = run.events.stream().filter(e -> e.contains("SKIPPED")).count(); p("failed=%d skipped=%d", failed, skipped); assertTrue(failed >= 2); } }