src/test/java/.../p4/<area>/).Add a regression test before fixing a bug; the test should fail without the fix.
org.junit.jupiter.api.*. Do not add JUnit 4
(org.junit.Test) tests.@WithJenkins — annotate the class with @WithJenkins and
receive JenkinsRule as a parameter (injected into @BeforeAll / test methods).mockito-core, test scope) — available for pure unit tests.org.junit.jupiter.api.Assertions.* (static imports).No server, no Jenkins. Test a single class's logic directly (e.g. parsing, validation, model objects). Prefer these — they are fast and deterministic. Use Mockito to isolate collaborators.
These exercise real Perforce + Jenkins behaviour. p4d does not need to be on
PATH — SimpleTestServer resolves the bundled binary under
src/test/resources/<version>/bin.<platform>/ by absolute path (picked from
os.name). Established pattern (see review/ReviewImplTest.java,
tagging/TaggingTest.java):
@WithJenkins
class MyFeatureTest extends DefaultEnvironment {
private static final String P4ROOT = "tmp-MyFeatureTest-p4root";
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 testSomething() throws Exception {
// build a PerforceScm with a Workspace + Populate, run a job, assert
}
}
Key building blocks:
DefaultEnvironment — base class with helpers (createCredentials,
defaultClient, checkpoint version constants like R24_1_r15, log capture).
Extend it for server-backed tests.SampleServerExtension — JUnit 5 extension that extracts a depot tarball,
restores a checkpoint, and tears the server down per test. Use a unique
P4ROOT per test class to avoid collisions.CREDENTIAL and defaultClient() helpers
rather than hand-rolling them.forkCount to the Jenkinsfile.P4ROOT directory name.SampleServerExtension.afterEach (destroy()); don't
leave servers running.mvn test # all tests
mvn test -Dtest=MyFeatureTest # one class
mvn package -DskipTests # build, skip tests (state this if you do it)
If you could not run tests (e.g. the bundled p4d won't execute on this
OS/arch), say so explicitly rather than implying they passed.
# Testing & TDD
## TDD workflow (default)
1. **Red** — write a failing test that expresses the desired behaviour. Put it in
the package mirroring the code under test (`src/test/java/.../p4/<area>/`).
2. **Green** — write the *minimum* production code to make it pass.
3. **Refactor** — clean up while keeping tests green. Re-run the test.
Add a regression test before fixing a bug; the test should fail without the fix.
## Frameworks in use
- **JUnit 5 (Jupiter)** — `org.junit.jupiter.api.*`. Do **not** add JUnit 4
(`org.junit.Test`) tests.
- **JenkinsRule via `@WithJenkins`** — annotate the class with `@WithJenkins` and
receive `JenkinsRule` as a parameter (injected into `@BeforeAll` / test methods).
- **Mockito** (`mockito-core`, test scope) — available for pure unit tests.
- Assertions: `org.junit.jupiter.api.Assertions.*` (static imports).
## Two kinds of tests here
### Pure unit tests
No server, no Jenkins. Test a single class's logic directly (e.g. parsing,
validation, model objects). Prefer these — they are fast and deterministic. Use
Mockito to isolate collaborators.
### Server-backed integration tests
These exercise real Perforce + Jenkins behaviour. **`p4d` does not need to be on
`PATH`** — `SimpleTestServer` resolves the bundled binary under
`src/test/resources/<version>/bin.<platform>/` by absolute path (picked from
`os.name`). Established pattern (see `review/ReviewImplTest.java`,
`tagging/TaggingTest.java`):
```java
@WithJenkins
class MyFeatureTest extends DefaultEnvironment {
private static final String P4ROOT = "tmp-MyFeatureTest-p4root";
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 testSomething() throws Exception {
// build a PerforceScm with a Workspace + Populate, run a job, assert
}
}
```
Key building blocks:
- **`DefaultEnvironment`** — base class with helpers (`createCredentials`,
`defaultClient`, checkpoint version constants like `R24_1_r15`, log capture).
Extend it for server-backed tests.
- **`SampleServerExtension`** — JUnit 5 extension that extracts a depot tarball,
restores a checkpoint, and tears the server down per test. Use a **unique
`P4ROOT`** per test class to avoid collisions.
- Reuse the credential id constant `CREDENTIAL` and `defaultClient()` helpers
rather than hand-rolling them.
## Rules
- **Do not run tests in parallel.** Tests share a real p4d server; parallel forks
were deliberately disabled. Don't re-add `forkCount` to the Jenkinsfile.
- Give each server-backed test class its own `P4ROOT` directory name.
- Clean up is handled by `SampleServerExtension.afterEach` (`destroy()`); don't
leave servers running.
- When you can express a behaviour as a pure unit test, do — reserve the
server-backed harness for genuine end-to-end SCM behaviour.
## Running
```bash
mvn test # all tests
mvn test -Dtest=MyFeatureTest # one class
mvn package -DskipTests # build, skip tests (state this if you do it)
```
If you could not run tests (e.g. the bundled `p4d` won't execute on this
OS/arch), say so explicitly rather than implying they passed.
| # | Change | User | Description | Committed | |
|---|---|---|---|---|---|
| #1 | 33896 | Sandeep Kumar | Add unit test to increase code covreage. |