---
name: write-test
description: Write a test for the P4 Jenkins plugin that covers every requirement / acceptance criterion, following the repo's JUnit 5 + JenkinsRule + p4d conventions. Use when asked to write or improve a test, add test coverage, or as the Red step of TDD before implementing a ticket.
---
# Write a Requirement-Complete Test
Produce a test (or extend one) that provably covers **every** acceptance
criterion of the requirement, using this repo's conventions. The goal is a test
that fails for the right reason before the code exists and passes once it does.
## Read first
- `.claude/guidelines/testing.md` — JUnit 5 / JenkinsRule / p4d harness patterns
- `.claude/guidelines/java-style.md` — tabs, imports, naming
## 1. Turn the requirement into a checklist
- List each acceptance criterion / behaviour as a separate, verifiable bullet.
- Include the **negative and edge cases** the requirement implies: null/empty
input, error paths from p4java, boundary values, "does nothing when…" cases.
- Each bullet must map to at least one assertion. Keep the checklist in scope —
don't invent requirements the ticket didn't state.
## 2. Choose the test type (smallest that proves the behaviour)
- **Pure unit test** (preferred): no Jenkins, no server. Test one class's logic
directly; use Mockito to isolate collaborators. Fast and deterministic.
- **Server-backed integration test**: only for genuine end-to-end SCM behaviour
that needs a real Perforce server. Does not need `p4d` on `PATH` — the
binary is bundled per-version/per-OS under `src/test/resources/` and
resolved automatically by `SimpleTestServer`.
## 3. Place and name it
- Mirror the package of the code under test in `src/test/java/.../p4//`.
- Name `Test`; methods `void testXxx()` describing the behaviour.
- One behaviour per `@Test` method — don't fold several criteria into one method
unless they're truly the same assertion.
## 4. Structure each test (Arrange / Act / Assert)
- **Arrange** the minimum fixture. Reuse `DefaultEnvironment` helpers
(`createCredentials`, `defaultClient`, checkpoint constants like `R24_1_r15`)
rather than hand-rolling setup.
- **Act** — invoke the behaviour under test once.
- **Assert** — use `org.junit.jupiter.api.Assertions.*`; assert the actual
outcome, not just "no exception". Prefer specific assertions
(`assertEquals(expected, actual)`) with a message when the intent isn't obvious.
### Server-backed skeleton
```java
@WithJenkins
class MyFeatureTest extends DefaultEnvironment {
private static final String P4ROOT = "tmp-MyFeatureTest-p4root"; // unique per class
private static JenkinsRule jenkins;
@RegisterExtension
private final SampleServerExtension p4d = new SampleServerExtension(P4ROOT, R24_1_r15);
@BeforeAll
static void beforeAll(JenkinsRule rule) {
jenkins = rule;
}
@BeforeEach
void beforeEach() throws Exception {
createCredentials("jenkins", "jenkins", p4d.getRshPort(), CREDENTIAL);
}
@Test
void testRequirementOne() throws Exception {
// arrange → act → assert
}
}
```
## 5. Conventions (must match)
- **JUnit 5 (Jupiter)** only — never `org.junit.Test` (JUnit 4).
- Server-backed: `@WithJenkins`, `extends DefaultEnvironment`,
`@RegisterExtension SampleServerExtension`, and a **unique `P4ROOT`** per class.
- **Tabs** for indentation; no wildcard imports.
- Do not run tests in parallel; don't add `forkCount`.
## 6. Prove it (Red, single test only)
- Run only this test: `mvn test -Dtest=MyFeatureTest`
(or `-Dtest=MyFeatureTest#testRequirementOne` for one method).
- In TDD it must **fail for the right reason** (an assertion gap, not a
compile/wiring error). If it passes before any code is written, the test isn't
actually exercising the new behaviour — fix it.
- If the bundled `p4d` won't run for a server-backed test (e.g. unsupported
OS/arch), say so explicitly.
## 7. Coverage check before finishing
- Re-read the step-1 checklist: every criterion (including edge/negative cases)
has a corresponding assertion. List any criterion you intentionally did not
cover and why.