From the free book Delta: Closing the Specification Gap (Dhuri, 2026). The PDF is the canonical edition — figures, tables, and code formatting are simplified online.
Edge case discovery, compilable test suites, and mutation-aware coverage analysis
“Your test suite tells you what you remembered to test. The edge case discovery prompt tells you what you forgot. The forgotten cases are the ones that go to production.” — A test suite with 90% line coverage and zero domain invariant tests is not a safe test suite. It is a false sense of security with a number on it.
1. Edge case discovery ranked #1 AI testing capability 2. Compilable JUnit 5 + Mockito and xUnit + NSubstitute suites 3. Spring Boot test slices: @WebMvcTest and @DataJpaTest 4. Mutation-aware test review without a mutation testing framework 5. Contract testing for microservices boundaries
76% of developers use or plan to use AI coding tools in their work. Edge case discovery as the single highest-value AI testing capability — above test skeleton generation, above coverage tools. It finds what developers forgot to think of. Source: Stack Overflow Developer Survey 2024 ( stackoverflow.com/survey/2024) See Research & Statistics Notes (see Appendix J)
BEFORE — Tier 1 (What most developers type) "Generate unit tests for this payment handler to reach 80% coverage." AFTER — Tier 3 (Specification Frame) "<role>Senior QA engineer specializing in production incident ,→ prevention.</role><method>{{paste method}}</method>< ,→ existing_tests>{{paste current tests}}</existing_tests><task> ,→ Find test cases NOT in existing tests. Focus on: BOUNDARY (at, ,→ one above, one below each boundary value), NULL/EMPTY (null ,→ params, empty collections), CONCURRENCY (shared state race ,→ conditions), DOMAIN FAILURES (valid individual inputs that ,→ violate a business rule in combination), ERROR PROPAGATION ( ,→ each dependency throwing each documented exception). Rank by ,→ production incident likelihood. Produce complete test methods ,→ for top 5. Test names must encode the specific scenario.</task ,→ >" Result: Tier 1 produces happy path + one or two obvious errors. Tier ,→ 3 produces the race condition test, the boundary value tests, ,→ the domain invariant test, and the error propagation tests — ,→ ranked by which would most likely reach production.
Java 21 — JUnit 5 + Mockito Payment Tests (Compilable) // File: src/test/java/com/yourcompany/payments/PaymentServiceTest. ,→ java package com.yourcompany.payments; import com.yourcompany.common.Money; import com.yourcompany.common.Result; import org.junit.jupiter.api.*; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.util.Optional; import java.util.UUID; import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) @DisplayName("PaymentService") class PaymentServiceTest { @Mock private PaymentRepository paymentRepository; @Mock private PaymentGateway gateway; @Mock private IdempotencyStore idempotencyStore; @InjectMocks private PaymentService sut; private static final UUID CUSTOMER = UUID.randomUUID(); private static final Money AMOUNT
= Money.of("99.99", "USD");
@BeforeEach void noIdempotencyHit() { when(idempotencyStore.get(anyString(), any())) .thenReturn(Optional.empty()); } @Test @DisplayName("returns Success with confirmation when gateway ,→ approves") void success_whenGatewayApproves() { when(gateway.charge(any(), anyString(), anyString())) .thenReturn(GatewayResponse.success("TXN-001")); var result = sut.processPayment( new ProcessPaymentCommand(CUSTOMER, AMOUNT, "tok_visa", " ,→ REF-1")); assertThat(result.isSuccess()).isTrue(); assertThat(result.getValueOrThrow().confirmationNumber()). ,→ isEqualTo("TXN-001"); verify(paymentRepository).save(any()); } @Test @DisplayName("returns cached confirmation without charging for ,→ duplicate reference") void returnsCached_forDuplicateRef_withoutCharging() { var cached = new PaymentConfirmation(UUID.randomUUID(), "TXN,→ ORIG"); when(idempotencyStore.get(eq("REF-DUP"), any())) .thenReturn(Optional.of(cached)); var result = sut.processPayment( new ProcessPaymentCommand(CUSTOMER, AMOUNT, "tok_visa", " ,→ REF-DUP")); assertThat(result.getValueOrThrow().confirmationNumber()). ,→ isEqualTo("TXN-ORIG"); verifyNoInteractions(gateway);
// must NOT charge for
,→ idempotent duplicate } @ParameterizedTest(name = "amount={0} USD should be rejected") @ValueSource(strings = {"0.00", "-0.01", "-100.00"}) @DisplayName("rejects non-positive amounts") void rejects_nonPositiveAmounts(String amountStr) { var result = sut.processPayment(new ProcessPaymentCommand( CUSTOMER, Money.of(amountStr, "USD"), "tok_visa", "REF-X") ,→ ); assertThat(result.isSuccess()).isFalse(); assertThat(result.getErrorCode()).isEqualTo("INVALID_AMOUNT"); ,→ } }
testing prompt because it finds what developers forgot to test — exactly what reaches production. + All examples are compilable. Java: JUnit 5 + @ExtendWith( MockitoExtension.class) + AssertJ. C#: xUnit + NSubstitute + FluentAssertions. No JUnit 5 patterns anywhere. + @ParameterizedTest/@ValueSource (Java) and [Theory]/ [InlineData] (C#) halve test method count for boundary tests. Use them for all boundary and equivalence class testing. + Spring Boot @WebMvcTest and @DataJpaTest slices load only the relevant layer. Converting @SpringBootTest to appropriate slices typically reduces test suite run time by 60–80%.
1. Apply edge case discovery to your most business-critical method. Rank uncovered cases by production incident likelihood. Implement the top three before the sprint ends. 2. Audit your test files: are any using JUnit 5 (@RunWith, org.junit. Test)? Migrate them to JUnit 5. 3. Convert one @SpringBootTest test class to @WebMvcTest or @DataJpaTest. Measure the run time difference.
UP NEXT — Chapter 10: Chaining and Multi-Agent Orchestration
One prompt, one task is the foundation. Chapter 10 scales it: the Four-Stage Pipeline for multi-step work, and how to keep specification quality intact when agents hand results to agents.
Chains, libraries, context layers, MCP, and the 2026 toolchain. Part I gave you the mental model. Part II gave you the recipes. Part III gives you the system. Individual prompt skill multiplies when it becomes team infrastructure: shared libraries, version-controlled prompts, automated context, and MCP-connected agents. The teams that invest in Part III in 2026 will be measurably more productive in 2027 than those who do not. This part shows you how.