使用方法
- 复制安装命令,在自己的智能体环境安装前先检查源码包。
- 从原始文档核对所需工具、凭据和支持的宿主。
- 说明输入材料与期望交付物,并对照来源检查输出。
npx skills add https://github.com/github/awesome-copilot --skill java-junit开始前需了解
- 安装不包含模型订阅、API 额度或访问文件的权限。
- 仓库星数和安装量反映活跃情况,不等于独立质量或安全测试。
按源仓库内容呈现,保留标题、案例、代码、表格、链接以及原文引用的演示图片。
Java Testing with JUnit 5/6, AssertJ and Mockito
Framework-neutral guidance for fast, deterministic unit tests. For Spring slices use spring-boot-testing (if installed); for real databases/brokers in Docker use java-testcontainers; for failures you cannot explain, java-debugging.
First: detect, don't impose
- Read
pom.xml/build.gradle*: JUnit version (junit-jupiter,junit-bom, or inherited from a Spring Boot BOM), assertion library, Mockito, Surefire/Failsafe versions, Java release. - Copy the conventions already in
src/test/java(naming, assertion library, static imports, mocking style). Do not introduce AssertJ, Mockito or JaCoCo into a project that lacks them without asking. - Never bump the JUnit major version implicitly; upgrading is its own task (see
java-upgradeif installed).
JUnit 5 vs JUnit 6
| JUnit 5 (last 5.14.x) | JUnit 6 (6.0 released; 6.1.x current) | |
|---|---|---|
| Java baseline | 8 | 17 (verified in the published Gradle module metadata) |
| Versioning | Platform 1.x, Jupiter 5.x, Vintage 5.x | One version number for Platform, Jupiter and Vintage |
| API | org.junit.jupiter.api.* | Same packages; the Jupiter tests in this skill compile and pass unchanged on 5.14.4 and 6.0.3 |
| Removed in 6.0 | MethodOrderer.Alphanumeric, the deprecated two-argument InvocationInterceptor.interceptDynamicTest(Invocation, ExtensionContext) overload (the three-argument one remains), junit.jupiter.tempdir.scope, @CsvFileSource(lineSeparator) | |
| CSV | univocity-parsers | FastCSV: stricter parsing (no characters after a closing quote); header-field options now apply to headers |
| Other | junit-jupiter-migrationsupport deprecated; invalid enum-style config values now fail discovery; @Nested class order deterministic but non-obvious |
Source: JUnit 6.0.0 release notes (<https://docs.junit.org/6.0.0/release-notes.html>). Read the notes for the target version (<https://docs.junit.org/current/release-notes/>) and prefer them over this table. JUnit 4 tests need the Vintage engine; do not mix org.junit.Test and org.junit.jupiter.api.Test in one class.
Dependencies (same for 5 and 6; verified with Maven and Gradle): import org.junit:junit-bom, then declare org.junit.jupiter:junit-jupiter (aggregates api, params, engine) with test scope. Gradle 9 additionally requires testRuntimeOnly("org.junit.platform:junit-platform-launcher") (verified: without it the test executor fails with "Failed to load JUnit Platform") and tasks.test { useJUnitPlatform() }. Maven needs Surefire 3.x (verified with 3.6.0).
Assertions
Match the project's library. Plain Jupiter rules: expected value first, lazy Supplier messages, assertAll, assertThrowsExactly, timeouts. (The separate instructions/java-junit5-assertions.instructions.md resource has the longer version but is not installed with this skill.) If the project uses AssertJ, prefer it for collections, strings and exceptions; patterns (soft assertions, assertThatThrownBy, extracting, containsExactly, usingRecursiveComparison) are in references/assertj-and-mockito.md.
- Assert on outcomes and state, not on how many times internals were called.
- Compare values; avoid bare
assertNotNull. - Never catch
AssertionError/Exceptionto make a test pass.
Mocking (Mockito)
- Mock collaborators across a boundary (repository, HTTP client, clock, message sender). Do not mock value objects, records, collections,
String, or the class under test; use real instances or simple fakes. - Prefer a hand-written fake over a mock when the interaction is stateful.
- Use
@ExtendWith(MockitoExtension.class)with@Mock/@InjectMocks/@Captor. Strict stubs are the default there, so an unused stub fails the test (UnnecessaryStubbingException). Fix the test; relax with@MockitoSettings(strictness = Strictness.LENIENT)only for a justified shared setup. - Mockito 5 uses the inline mock maker by default. On JDK 21+ it may self-attach and print a dynamic-agent warning. With Mockito 5.14.0+, register
mockito-coreas a-javaagentinstead (setup for Maven and Gradle inreferences/assertj-and-mockito.md, verified on JDK 21 and 25). Check the resolved version first: earlier 5.x jars lackPremain-Classand cannot be used as the agent. Ask before upgrading; otherwise use the instrumentation setup documented for the installed version. - Mockito 5 requires Java 11+. Its default inline mock maker does not work on GraalVM native image, where the subclass mock maker is appropriate (Mockito 5.0.0 release notes, <https://github.com/mockito/mockito/releases/tag/v5.0.0>).
- Avoid
mockStatic/mockConstruction; wrap the static call behind an interface.
Determinism
- Time: inject
java.time.Clock(Clock.fixed(...)) and callInstant.now(clock); avoidInstant.now()/LocalDate.now()in code under test. - Randomness: inject a
Random/RandomGeneratorwith a fixed seed; log the seed if generated. - Do not depend on default locale, time zone, file encoding, network, or wall-clock sleeps. Set them explicitly (newer 6.x releases add built-in locale/time-zone/system-property extensions; check the release notes of your version, otherwise use try/finally).
Unit vs integration tests
Unit (*Test) | Integration (*IT) | |
|---|---|---|
| Maven | Surefire, mvn test | Failsafe, mvn verify |
| Gradle | test task | separate integrationTest task (JVM Test Suite) wired into check |
| Speed | milliseconds, no I/O | may use Docker/DB |
Surefire defaults pick *Test, Test*, *Tests, *TestCase; Failsafe picks *IT, IT*, *ITCase. Failsafe needs the integration-test and verify goals bound and is run by mvn verify, not mvn test. Alternatively split by @Tag. For databases and brokers see java-testcontainers; for Spring slices see spring-boot-testing. Full build snippets: references/build-setup.md.
Coverage and mutation testing (optional)
- JaCoCo: add only if the project uses it or the user asks. With Surefire/Failsafe use
<argLine>@{argLine} ...</argLine>so the JaCoCo agent is not overwritten. - Coverage is a smell detector, not a goal; never add assertion-free tests to raise a number, and do not add a coverage gate the project lacks.
- PIT (mutation testing) is slow; run it on changed classes only if the project already uses it or the user asks (see
references/build-setup.md, which records a verified pitest-maven + JUnit 5 plugin run).
Agent guardrails
- Never delete, comment out,
@Disabled, weaken (looser assertion, wider tolerance, swallowed exception) or skip a failing test to get green. Find the cause. - Decide which side is wrong, the test or the production code. If the fix changes production behavior, stop and ask the user first; if the test encodes an obviously stale expectation, say so and propose the change.
- Do not add
-DskipTests,-Dmaven.test.skip,-x testorfailIfNoTests=falseto make a build pass. - Do not mock the class under test or assert on mock internals to "prove" correctness.
- Run the narrowest test first, then the full build:
- Maven:
mvn -q -Dtest=OrdersTest test(one method:-Dtest='OrdersTest#place_should_saveAndNotify_when_itemValid'), thenmvn verify. - Gradle:
./gradlew test --tests 'demo.OrdersTest', then./gradlew check.
Prefer the project wrapper (./mvnw, ./gradlew) when present.
- Flaky test: reproduce by rerunning, then remove the nondeterminism (time, order, shared state, async waits); do not add retries.
- New code gets new tests beside the existing ones, in the same style: happy path, boundaries, error cases.
References
references/assertj-and-mockito.md: AssertJ patterns, Mockito strictness/captors/agent setup, when not to mock.references/build-setup.md: Maven and Gradle (Kotlin DSL) setups for JUnit 5/6, Failsafe split, JaCoCo, PIT.

