| name | paw-testing-layer |
| description | Use when creating, changing, auditing, or repairing PAW Forkd blackbox tests, Maven verification gates, test fixtures, HSQLDB/JPA persistence tests, service tests, MVC/security/API tests, template/frontend tests, or test failures. |
Paw Testing Layer
Overview
Use this as the transversal testing skill for PAW/Forkd. It encodes the PAW-Wiki testing rules and the repo-specific Maven/test habits needed to avoid false confidence.
Read references/testing-rules.md before writing, repairing, or judging tests.
Test Selection
Choose the test type from the behavior under test:
- Business rule or state transition: service test.
- SQL, row mapping, constraints, ordering, pagination, or schema behavior: DAO/persistence test against HSQLDB.
- TP2 JPA mapping, fetch, cascade, dirty checking, or generated SQL behavior: persistence/context test plus SQL/log inspection where useful.
- Route, binding, validation error, security rule, redirect, or JSP model contract: webapp MVC/security test.
- TP final REST resource status/body/header/error contract: API/MVC/JAX-RS resource test.
- SPA stores/composables, routes, forms, errors, and i18n behavior: frontend test if the repo has a frontend test runner; otherwise document the gap and manual/contract verification.
- API cache/static hosting behavior: cache/smoke test for
ETag, If-None-Match, 304, and asset cache headers.
- TP final WAR contents and route split: packaging/smoke check.
- JSP escaping, scriptlets, i18n bundle symmetry, or rendered-template contract: template/i18n test.
- Runtime wiring, AOP proxy, scheduler, or app startup behavior: context/integration test or Jetty smoke.
Core Rules
- Tests are blackbox: assert externally observable behavior or final state, not internal calls.
- One test covers one scenario and one action. If the name needs "and", split it.
- Never use
Mockito.verify, never, verifyNoInteractions, spy, or hand-rolled equivalents that count whether a dependency method was called.
- Never test private methods, reflection paths, or
Class.forName seams. Exercise private logic only through public behavior.
- DAO tests use HSQLDB, shared schema bootstrap, SQL fixtures/direct setup,
@Rollback, and DB state assertions.
- Service tests mock DAOs but assert returned state, thrown exceptions, state transitions, or recorded side effects.
- Do not test services that are pure pass-through wrappers; move/test real business behavior where it belongs.
- MVC tests verify status, redirects, model/binding errors, security, and preserved GET state.
- API contract tests verify status, DTO body, Problem Details, media types, auth errors, and headers such as
Location, Link, ETag, and CORS-exposed headers.
- API 404 tests must prove
/api/* returns JSON/Problem Details, while SPA deep links fall back to index.html.
- Cache tests prove both validator flow (
ETag -> If-None-Match -> 304) and static cache policy when cache is implemented.
- Frontend tests cover stores/composables/routes/forms/i18n at the public UI/state contract level, not component internals.
- Frontend tests must not assert component internals, exact CSS classes, source snippets, exact DOM shape, implementation-specific store calls, or framework internals as the target.
- Do not use the object under test to set its own preconditions.
- Cover happy, unhappy, and edge paths as separate tests.
- A green build is not proof of wiki compliance; inspect test style and coverage against the rules.
TDD Flow
When implementing a feature or bugfix, follow Superpowers test-driven-development:
- Write one failing test for the next behavior.
- Run the narrow command and verify the failure is for the expected reason.
- Implement the smallest production change.
- Re-run the narrow command until green.
- Refactor only after green.
- Run the broader gate for the changed modules.
For TP final migration, apply this per vertical slice. Start with the public API/resource contract test for the flow, then add service tests only for changed business behavior, then SPA/frontend tests for route/client/state/form/i18n behavior when a runner exists. If no frontend runner exists, define and run a repeatable browser/static-hosting smoke. Do not treat a slice as done until the API contract and user-visible SPA behavior have both been verified or an explicit gap is recorded.
Maven Gates
Use the narrowest meaningful command first:
mvn -pl persistence -am -Dtest=<DaoTestName> test
mvn -pl services -am -Dtest=<ServiceTestName> test
mvn -pl webapp -am -Dtest=<MvcTestName> -Dsurefire.failIfNoSpecifiedTests=false test
mvn -pl webapp -am test
mvn clean test
mvn clean package
Use -am for tests that depend on upstream modules. For targeted webapp tests, include -Dsurefire.failIfNoSpecifiedTests=false so upstream modules without that test pattern do not fail before the target module runs. For TP final, mvn clean package is a gate, not an afterthought: inspect the WAR for index.html, JS/CSS/assets, and backend classes.
When frontend/ exists, read frontend/package.json and run the declared test/type-check/build scripts that match the slice. Prefer the repo's package-manager/lockfile workflow (npm ci for package-lock unless the repo says otherwise). If packaging changed, follow with mvn clean package and WAR inspection.
Review Checklist
- Does each test name describe a behavior, not an implementation detail?
- Does setup avoid using the method/class under test?
- Does the test perform one public action and assert one scenario?
- Does validation assert observable behavior or final state without another method on the same subject under test?
- Are DAO tests checking real DB state?
- Are DB writes validated with direct SQL/JdbcTestUtils, including the expected actor/user when relevant?
- Are there no
verify, spy, reflection, lenient, interaction counters, or no-assert tests?
- Are service tests not pretending to prove Spring proxy/AOP behavior when they instantiate implementations directly?
- Do TP final tests cover API headers/errors, API 404 vs SPA fallback, cache
304, frontend stores/composables/routes/forms/i18n, and WAR contents when those surfaces exist?
- Is a pass-through service test deleted or replaced by a test for real business behavior?
- Does the final gate match the blast radius of the change?
- For TP final migration, does the slice have a named first failing test, API + SPA verification, package/static-hosting gate when touched, and a rollback/parallel-route state?
- If no frontend runner exists, is there a repeatable smoke command/result rather than a prose-only gap?