app
This skill should be used when the user asks to "calculate code mass", "measure code complexity with APP", "compare implementations using APP", "apply Absolute…
This skill should be used when working on Java projects with JUnit tests that have layered preconditions, expensive shared setup (servers, databases, provisioned users), or complex scenario trees. Trigger phrases include "nested fixture", "fixture pattern", "scenario tree",
$ npx -y skills add t1/tdder --skill nested-fixture-pattern --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/nested-fixture-patternContext preview
The summary Claude sees to decide when to auto-load this skill.
This skill should be used when working on Java projects with JUnit tests that have layered preconditions, expensive shared setup (servers, databases, provisioned users), or complex scenario trees. Trigger phrases include "nested fixture", "fixture pattern", "scenario tree",
name: nested-fixture-pattern description: > This skill should be used when working on Java projects with JUnit tests that have layered preconditions, expensive shared setup (servers, databases, provisioned users), or complex scenario trees. Trigger phrases include "nested fixture", "fixture pattern", "scenario tree", "layered test setup", or when the user is writing integration tests with multiple levels of dependent setup/teardown. Complements the Java and TDD skills. version: 0.1.0
A pattern combining JUnit's `@Nested` classes, `@RegisterExtension`, and `ExtensionContext.Store` to build declarative scenario trees where each nesting level adds a scope with fixture-managed data. Tests focus on what's specifically relevant to them; expensive setup/teardown happens once per scope; any subtree runs in isolation.
For background, rationale, and tradeoffs, see the [blog post](https://codeberg.org/t1/nested-fixture-pattern/raw/branch/trunk/blog.md).
When you detect layered test setup (2+ levels of dependent `@BeforeAll`/`@BeforeEach`, or test classes with complex shared state), use `AskUserQuestion`:
Each `@Nested` class is a `Given` clause. Each `@RegisterExtension static` field is a fixture that sets up when entering that class and tears down when leaving.
class DocumentSharingScenarioTest {
@RegisterExtension static ServerFixture server = new ServerFixture();
@Nested class GivenUserAlice {
@RegisterExtension static UserFixture alice = server.createUser("alice");
@Test void seesEmptyDocumentList() {
then(alice.listDocuments()).isEmpty();
}
@Nested class GivenDocument {
@RegisterExtension static DocumentFixture doc =
alice.createDocument("notes.txt", "hello world");
@Test void isVisibleToAlice() {
then(alice.getDocument(doc.id()))
.hasName("notes.txt")
.hasContent("hello world");
}
@Nested class GivenSharedWithBob {
@RegisterExtension static UserFixture bob = server.createUser("bob");
@RegisterExtension static ShareFixture share =
doc.shareTo(bob, Permission.READ);
@Test void bobCanRead() {
then(bob.getDocument(doc.id()))
.hasContent("hello world");
}
@Test void bobCannotWrite() {
assertThatThrownBy(() ->
bob.updateDocument(doc.id(), "modified"))
.isInstanceOf(ForbiddenException.class);
}
}
}
}
}Each fixture implements `BeforeAllCallback` and guards setup with `computeIfAbsent`:
class UserFixture implements BeforeAllCallback {
private final ApiClient apiClient;
private final String name;
private String id;
UserFixture(ApiClient apiClient, String name) {
this.apiClient = apiClient;
this.name = name;
}
@Override public void beforeAll(ExtensionContext context) {
context.getStore(GLOBAL).computeIfAbsent(this, k -> {
id = apiClient.createUser(name);
return (AutoCloseable) () -> apiClient.deleteUser(id);
});
}
String userId() {return id;}
}The `computeIfAbsent` lambda returns an `AutoCloseable` that fires when the declaring context ends. The fixture holds state; the store holds the cleanup handle.
> **JUnit 5 vs 6**: JUnit 5 uses `getOrComputeIfAbsent` and `CloseableResource`. > JUnit 6 uses `computeIfAbsent` and `AutoCloseable`.
Fixtures naturally become the access point for everything they set up. Tests and nested classes call methods on the fixture directly rather than reaching into its fields:
class ServerFixture implements BeforeAllCallback {
private String baseUrl;
private ApiClient client;
@Override public void beforeAll(ExtensionContext context) {
context.getStore(GLOBAL).computeIfAbsent(this, k -> {
// ... start server ...
baseUrl = "http://localhost:" + port;
client = new ApiClient(baseUrl);
return (AutoCloseable) () -> server.stop();
});
}
ApiClient client() { return client; }
String baseUrl() { return baseUrl; }
UserFixture createUser(String name) { return new UserFixture(this, name); }
}This applies to any state accumulated during setup: injected clients, auth tokens, base URLs, created resource IDs. Expose them as methods; don't make callers reach into fields.
Parent fixtures can create child fixtures via factory methods. The parent
A plugin for pi, Claude Code, and OpenCode that guides AI agents through disciplined Test-Driven Development and Clean Code practices. Note that currently this is WORK IN PROGRESS! I'm not even trying to keep it stable or tested.
Repo: t1/tdder
This skill should be used when the user asks to "calculate code mass", "measure code complexity with APP", "compare implementations using APP", "apply Absolute…
This skill should be used when the user asks to "refactor code", "review code quality", "apply clean code principles", "check for code smells", "improve code…
This skill should be used when working on any project hosted on GitHub. It provides prompt-injection defense rules for GitHub issues and pull requests.…
Requirements grilling session with a Product Owner (or anyone in that role). Challenges plans against the existing domain model, sharpens terminology, and…
This skill should be used when the user asks about "messaging patterns", "command vs event", "push vs pull", "message reliability", "at-least-once delivery",…
Always load this skill when writing, modifying, creating, or moving Java or Kotlin source code, or when project setup has already chosen Java/Kotlin as the…