One test per question, each writing and asserting its own transcript under output/. Covers lifecycle, extensions, parameterized and dynamic tests, mocks vs spies, verification, strict stubs, static and constructor mocking, and flaky tests. Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01CifR2BE7PBvRy5hT8TS9oz
118 lines
3.7 KiB
Java
118 lines
3.7 KiB
Java
package lab.jm.fixtures;
|
|
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
import org.junit.jupiter.api.Test;
|
|
import org.junit.jupiter.api.TestInfo;
|
|
import org.junit.jupiter.api.extension.AfterAllCallback;
|
|
import org.junit.jupiter.api.extension.AfterEachCallback;
|
|
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
|
|
import org.junit.jupiter.api.extension.BeforeAllCallback;
|
|
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
|
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
|
|
import org.junit.jupiter.api.extension.ExtendWith;
|
|
import org.junit.jupiter.api.extension.ExtensionContext;
|
|
import org.junit.jupiter.api.extension.ParameterContext;
|
|
import org.junit.jupiter.api.extension.ParameterResolver;
|
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
|
|
|
public final class ExtensionFixtures {
|
|
private ExtensionFixtures() {
|
|
}
|
|
|
|
/** Logs every callback it receives, tagged with a label. */
|
|
public static class Tracer implements BeforeAllCallback, BeforeEachCallback,
|
|
BeforeTestExecutionCallback, AfterTestExecutionCallback, AfterEachCallback, AfterAllCallback {
|
|
private final String label;
|
|
|
|
public Tracer() {
|
|
this("declared");
|
|
}
|
|
|
|
public Tracer(String label) {
|
|
this.label = label;
|
|
}
|
|
|
|
@Override
|
|
public void beforeAll(ExtensionContext c) {
|
|
Log.add(label + ": beforeAll");
|
|
}
|
|
|
|
@Override
|
|
public void beforeEach(ExtensionContext c) {
|
|
Log.add(label + ": beforeEach");
|
|
}
|
|
|
|
@Override
|
|
public void beforeTestExecution(ExtensionContext c) {
|
|
Log.add(label + ": beforeTestExecution");
|
|
}
|
|
|
|
@Override
|
|
public void afterTestExecution(ExtensionContext c) {
|
|
Log.add(label + ": afterTestExecution");
|
|
}
|
|
|
|
@Override
|
|
public void afterEach(ExtensionContext c) {
|
|
Log.add(label + ": afterEach");
|
|
}
|
|
|
|
@Override
|
|
public void afterAll(ExtensionContext c) {
|
|
Log.add(label + ": afterAll");
|
|
}
|
|
}
|
|
|
|
/** One declarative extension, to show the callback order around a test and its @BeforeEach method. */
|
|
@ExtendWith(Tracer.class)
|
|
public static class CallbackOrder {
|
|
@BeforeEach
|
|
void beforeEachMethod() {
|
|
Log.add("test class: @BeforeEach method");
|
|
}
|
|
|
|
@Test
|
|
void theTest() {
|
|
Log.add("test class: the test body");
|
|
}
|
|
}
|
|
|
|
/** Declarative (@ExtendWith) and programmatic (@RegisterExtension) side by side. */
|
|
@ExtendWith(Tracer.class)
|
|
public static class Registration {
|
|
@RegisterExtension
|
|
static final Tracer PROGRAMMATIC = new Tracer("programmatic(static field)");
|
|
|
|
@Test
|
|
void theTest() {
|
|
Log.add("test body");
|
|
}
|
|
}
|
|
|
|
/** A value the custom resolver hands to tests. */
|
|
public record Tenant(String name) {
|
|
}
|
|
|
|
/** Resolves Tenant parameters, in constructors and in test methods alike. */
|
|
public static class TenantResolver implements ParameterResolver {
|
|
@Override
|
|
public boolean supportsParameter(ParameterContext p, ExtensionContext c) {
|
|
return p.getParameter().getType() == Tenant.class;
|
|
}
|
|
|
|
@Override
|
|
public Object resolveParameter(ParameterContext p, ExtensionContext c) {
|
|
return new Tenant("tenant-for-" + c.getRequiredTestMethod().getName());
|
|
}
|
|
}
|
|
|
|
@ExtendWith(TenantResolver.class)
|
|
public static class Injection {
|
|
@Test
|
|
void resolvesCustomAndBuiltIn(Tenant tenant, TestInfo info) {
|
|
Log.add("custom parameter : " + tenant);
|
|
Log.add("built-in TestInfo: displayName=" + info.getDisplayName());
|
|
}
|
|
}
|
|
}
|