# 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//`). 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//bin./` 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.