gradle-testing-setup
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGradle Testing Setup
Gradle 测试环境搭建
Table of Contents
目录
When to Use This Skill
何时使用本技能
Use this skill when you need to:
- Set up JUnit 5 (Jupiter) testing framework
- Configure TestContainers for integration tests with real databases
- Separate unit tests from integration tests
- Measure code coverage with JaCoCo
- Enforce minimum code coverage thresholds
- Configure parallel test execution for faster test runs
- Set up test logging and reporting in CI/CD
- Create separate source sets for integration tests
当你需要以下功能时可使用本技能:
- 搭建JUnit 5(Jupiter)测试框架
- 配置TestContainers以使用真实数据库进行集成测试
- 分离单元测试与集成测试
- 使用JaCoCo统计代码覆盖率
- 强制执行最低代码覆盖率阈值
- 配置并行测试执行以加快测试运行速度
- 在CI/CD中配置测试日志与报告
- 为集成测试创建独立的源码集
Quick Start
快速开始
Add to :
build.gradle.ktskotlin
dependencies {
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("org.testcontainers:testcontainers:1.21.0")
testImplementation("org.testcontainers:junit-jupiter:1.21.0")
testImplementation("org.testcontainers:postgresql:1.21.0")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
plugins {
id("jacoco")
}
tasks.test {
useJUnitPlatform()
}
tasks.jacocoTestReport {
dependsOn(tasks.test)
finalizedBy(tasks.jacocoTestCoverageVerification)
}
tasks.check {
dependsOn(tasks.jacocoTestReport)
}Run tests:
bash
./gradlew test # Run unit tests
./gradlew test jacocoTestReport # With coverage report
./gradlew integrationTest # Run integration tests (if configured)在中添加以下配置:
build.gradle.ktskotlin
dependencies {
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("org.testcontainers:testcontainers:1.21.0")
testImplementation("org.testcontainers:junit-jupiter:1.21.0")
testImplementation("org.testcontainers:postgresql:1.21.0")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
plugins {
id("jacoco")
}
tasks.test {
useJUnitPlatform()
}
tasks.jacocoTestReport {
dependsOn(tasks.test)
finalizedBy(tasks.jacocoTestCoverageVerification)
}
tasks.check {
dependsOn(tasks.jacocoTestReport)
}运行测试:
bash
./gradlew test # 运行单元测试
./gradlew test jacocoTestReport # 生成覆盖率报告
./gradlew integrationTest # 运行集成测试(已配置的情况下)Instructions
操作步骤
Step 1: Configure JUnit 5 (Jupiter)
步骤1:配置JUnit 5(Jupiter)
Add JUnit 5 dependencies:
kotlin
dependencies {
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.junit.jupiter:junit-jupiter:5.11.0")
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.11.0")
}
tasks.test {
useJUnitPlatform()
}Advanced JUnit 5 configuration:
kotlin
tasks.test {
useJUnitPlatform {
// Include/exclude tags
includeTags("unit", "integration")
excludeTags("slow", "manual")
// Include/exclude by engine
includeEngines("junit-jupiter")
excludeEngines("junit-vintage")
}
// Filter tests by pattern
filter {
includeTestsMatching("*Test")
includeTestsMatching("*Tests")
excludeTestsMatching("*IntegrationTest")
}
// Parallel test execution
maxParallelForks = Runtime.getRuntime().availableProcessors() / 2
// System properties for tests
systemProperty("junit.jupiter.execution.parallel.enabled", "true")
systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent")
// Detailed logging
testLogging {
events("passed", "skipped", "failed", "standardOut")
showExceptions = true
showStackTraces = true
showCauses = true
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
}添加JUnit 5依赖:
kotlin
dependencies {
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.junit.jupiter:junit-jupiter:5.11.0")
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.11.0")
}
tasks.test {
useJUnitPlatform()
}JUnit 5高级配置:
kotlin
tasks.test {
useJUnitPlatform {
// 包含/排除标签
includeTags("unit", "integration")
excludeTags("slow", "manual")
// 包含/排除测试引擎
includeEngines("junit-jupiter")
excludeEngines("junit-vintage")
}
// 按模式过滤测试
filter {
includeTestsMatching("*Test")
includeTestsMatching("*Tests")
excludeTestsMatching("*IntegrationTest")
}
// 并行测试执行
maxParallelForks = Runtime.getRuntime().availableProcessors() / 2
// 测试系统属性
systemProperty("junit.jupiter.execution.parallel.enabled", "true")
systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent")
// 详细日志
testLogging {
events("passed", "skipped", "failed", "standardOut")
showExceptions = true
showStackTraces = true
showCauses = true
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
}Step 2: Set Up TestContainers for Integration Tests
步骤2:为集成测试配置TestContainers
Add TestContainers dependencies:
kotlin
dependencies {
testImplementation("org.testcontainers:testcontainers:1.21.0")
testImplementation("org.testcontainers:junit-jupiter:1.21.0")
testImplementation("org.testcontainers:postgresql:1.21.0")
testImplementation("org.testcontainers:gcloud:1.21.0") // For Pub/Sub emulator
}
tasks.test {
useJUnitPlatform()
// Docker socket configuration
systemProperty("testcontainers.reuse.enable", "true")
}Example integration test with TestContainers:
java
@SpringBootTest
@Testcontainers
class SupplierChargesIntegrationTest {
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")
.withDatabaseName("testdb")
.withUsername("test")
.withPassword("test");
@Container
static GenericContainer<?> pubsub = new GenericContainer<>("google/cloud-sdk:emulators")
.withExposedPorts(8085)
.withCommand("gcloud", "beta", "emulators", "pubsub", "start", "--host-port=0.0.0.0:8085");
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
registry.add("spring.cloud.gcp.pubsub.emulator-host",
() -> "localhost:" + pubsub.getMappedPort(8085));
}
@Test
void testDatabaseAndPubSub() {
// Test with real PostgreSQL and Pub/Sub emulator
}
}添加TestContainers依赖:
kotlin
dependencies {
testImplementation("org.testcontainers:testcontainers:1.21.0")
testImplementation("org.testcontainers:junit-jupiter:1.21.0")
testImplementation("org.testcontainers:postgresql:1.21.0")
testImplementation("org.testcontainers:gcloud:1.21.0") // 用于Pub/Sub模拟器
}
tasks.test {
useJUnitPlatform()
// Docker套接字配置
systemProperty("testcontainers.reuse.enable", "true")
}使用TestContainers的集成测试示例:
java
@SpringBootTest
@Testcontainers
class SupplierChargesIntegrationTest {
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")
.withDatabaseName("testdb")
.withUsername("test")
.withPassword("test");
@Container
static GenericContainer<?> pubsub = new GenericContainer<>("google/cloud-sdk:emulators")
.withExposedPorts(8085)
.withCommand("gcloud", "beta", "emulators", "pubsub", "start", "--host-port=0.0.0.0:8085");
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
registry.add("spring.cloud.gcp.pubsub.emulator-host",
() -> "localhost:" + pubsub.getMappedPort(8085));
}
@Test
void testDatabaseAndPubSub() {
// 使用真实PostgreSQL和Pub/Sub模拟器进行测试
}
}Step 3: Separate Unit and Integration Tests
步骤3:分离单元测试与集成测试
Create separate source sets and tasks:
kotlin
sourceSets {
create("integrationTest") {
java {
srcDir("src/integrationTest/java")
compileClasspath += sourceSets.main.get().output + sourceSets.test.get().output
runtimeClasspath += sourceSets.main.get().output + sourceSets.test.get().output
}
resources {
srcDir("src/integrationTest/resources")
}
}
}
// Create integration test task
val integrationTest = tasks.register<Test>("integrationTest") {
description = "Run integration tests"
group = "verification"
testClassesDirs = sourceSets["integrationTest"].output.classesDirs
classpath = sourceSets["integrationTest"].runtimeClasspath
useJUnitPlatform()
// Run after unit tests
shouldRunAfter(tasks.test)
// Logging
testLogging {
events("passed", "skipped", "failed")
}
}
// Include integration tests in overall check
tasks.check {
dependsOn(integrationTest)
}Directory structure:
src/
├── main/
│ └── java/
├── test/ # Unit tests
│ ├── java/
│ │ └── com/example/
│ │ ├── ServiceTest.java
│ │ └── ControllerTest.java
│ └── resources/
│ └── application-test.yml
└── integrationTest/ # Integration tests
├── java/
│ └── com/example/
│ └── ServiceIntegrationTest.java
└── resources/
└── application-integration.yml创建独立的源码集和任务:
kotlin
sourceSets {
create("integrationTest") {
java {
srcDir("src/integrationTest/java")
compileClasspath += sourceSets.main.get().output + sourceSets.test.get().output
runtimeClasspath += sourceSets.main.get().output + sourceSets.test.get().output
}
resources {
srcDir("src/integrationTest/resources")
}
}
}
// 创建集成测试任务
val integrationTest = tasks.register<Test>("integrationTest") {
description = "Run integration tests"
group = "verification"
testClassesDirs = sourceSets["integrationTest"].output.classesDirs
classpath = sourceSets["integrationTest"].runtimeClasspath
useJUnitPlatform()
// 在单元测试后运行
shouldRunAfter(tasks.test)
// 日志配置
testLogging {
events("passed", "skipped", "failed")
}
}
// 将集成测试纳入整体检查流程
tasks.check {
dependsOn(integrationTest)
}目录结构:
src/
├── main/
│ └── java/
├── test/ # 单元测试
│ ├── java/
│ │ └── com/example/
│ │ ├── ServiceTest.java
│ │ └── ControllerTest.java
│ └── resources/
│ └── application-test.yml
└── integrationTest/ # 集成测试
├── java/
│ └── com/example/
│ └── ServiceIntegrationTest.java
└── resources/
└── application-integration.ymlStep 4: Configure Code Coverage with JaCoCo
步骤4:使用JaCoCo配置代码覆盖率
Add JaCoCo plugin and configuration:
kotlin
plugins {
id("jacoco")
}
jacoco {
toolVersion = "0.8.12"
}
tasks.jacocoTestReport {
dependsOn(tasks.test)
reports {
xml.required = true
html.required = true
csv.required = false
xml.outputLocation = layout.buildDirectory.file("reports/jacoco/test/jacocoTestReport.xml")
html.outputLocation = layout.buildDirectory.dir("reports/jacoco/test/html")
}
finalizedBy(tasks.jacocoTestCoverageVerification)
}
// Enforce coverage minimums
tasks.jacocoTestCoverageVerification {
violationRules {
// Overall coverage requirement
rule {
element = "BUNDLE"
limit {
minimum = BigDecimal("0.60") // 60% minimum
}
}
// Class-level requirements
rule {
element = "CLASS"
excludes = listOf("**/config/*", "**/dto/*")
limit {
counter = "LINE"
value = "COVEREDRATIO"
minimum = BigDecimal("0.50") // 50% per class
}
}
// Method-level requirements
rule {
element = "METHOD"
limit {
counter = "LINE"
value = "COVEREDRATIO"
minimum = BigDecimal("0.40") // 40% per method
}
}
}
}
// Generate report after tests
tasks.test {
finalizedBy(tasks.jacocoTestReport)
}
// Include in overall check
tasks.check {
dependsOn(tasks.jacocoTestReport)
}添加JaCoCo插件与配置:
kotlin
plugins {
id("jacoco")
}
jacoco {
toolVersion = "0.8.12"
}
tasks.jacocoTestReport {
dependsOn(tasks.test)
reports {
xml.required = true
html.required = true
csv.required = false
xml.outputLocation = layout.buildDirectory.file("reports/jacoco/test/jacocoTestReport.xml")
html.outputLocation = layout.buildDirectory.dir("reports/jacoco/test/html")
}
finalizedBy(tasks.jacocoTestCoverageVerification)
}
// 强制执行最低覆盖率要求
tasks.jacocoTestCoverageVerification {
violationRules {
// 整体覆盖率要求
rule {
element = "BUNDLE"
limit {
minimum = BigDecimal("0.60") // 最低60%
}
}
// 类级别覆盖率要求
rule {
element = "CLASS"
excludes = listOf("**/config/*", "**/dto/*")
limit {
counter = "LINE"
value = "COVEREDRATIO"
minimum = BigDecimal("0.50") // 每个类最低50%
}
}
// 方法级别覆盖率要求
rule {
element = "METHOD"
limit {
counter = "LINE"
value = "COVEREDRATIO"
minimum = BigDecimal("0.40") // 每个方法最低40%
}
}
}
}
// 测试完成后生成报告
tasks.test {
finalizedBy(tasks.jacocoTestReport)
}
// 将覆盖率检查纳入整体流程
tasks.check {
dependsOn(tasks.jacocoTestReport)
}Step 5: Configure Test Logging
步骤5:配置测试日志
Use prettier test output with test-logger plugin:
kotlin
plugins {
id("com.adarshr.test-logger") version "4.0.0"
}
testlogger {
theme = "mocha" // Options: plain, standard, mocha, standard-parallel, mocha-parallel
showExceptions = true
showStackTraces = true
showFullStackTraces = false
showCauses = true
slowThreshold = 2000 // Warn for tests > 2 seconds
showSummary = true
showPassed = true
showSkipped = true
showFailed = true
showStandardStreams = false
}使用test-logger插件优化测试输出:
kotlin
plugins {
id("com.adarshr.test-logger") version "4.0.0"
}
testlogger {
theme = "mocha" // 可选主题:plain, standard, mocha, standard-parallel, mocha-parallel
showExceptions = true
showStackTraces = true
showFullStackTraces = false
showCauses = true
slowThreshold = 2000 // 测试耗时超过2秒时发出警告
showSummary = true
showPassed = true
showSkipped = true
showFailed = true
showStandardStreams = false
}Step 6: Configure Docker for TestContainers
步骤6:为TestContainers配置Docker
Ensure Docker is properly configured:
bash
undefined确保Docker已正确配置:
bash
undefinedVerify Docker is running
验证Docker是否运行
docker ps
docker ps
On macOS with Docker Desktop
在macOS的Docker Desktop环境下
export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock
export DOCKER_HOST=unix://${HOME}/.docker/run/docker.sock
export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock
export DOCKER_HOST=unix://${HOME}/.docker/run/docker.sock
Run tests
运行测试
./gradlew test
In `gradle.properties` for CI/CD:
```properties
org.gradle.logging.level=info
testcontainers.reuse.enable=true./gradlew test
在CI/CD的`gradle.properties`中配置:
```properties
org.gradle.logging.level=info
testcontainers.reuse.enable=trueExamples
示例
Example: Running Different Test Suites
示例:运行不同测试套件
bash
undefinedbash
undefinedUnit tests only
仅运行单元测试
./gradlew test
./gradlew test
Integration tests only
仅运行集成测试
./gradlew integrationTest
./gradlew integrationTest
All tests
运行所有测试
./gradlew check
./gradlew check
With coverage report
生成覆盖率报告
./gradlew test jacocoTestReport
./gradlew test jacocoTestReport
Specific test class
运行指定测试类
./gradlew test --tests "com.example.ServiceTest"
./gradlew test --tests "com.example.ServiceTest"
Tests matching pattern
运行匹配模式的测试
./gradlew test --tests "*IntegrationTest"
./gradlew test --tests "*IntegrationTest"
Single test method
运行单个测试方法
./gradlew test --tests "com.example.ServiceTest.testMethod"
./gradlew test --tests "com.example.ServiceTest.testMethod"
Verbose output
详细输出
./gradlew test --info
./gradlew test --info
Continuous mode (rerun on changes)
持续模式(代码变更时自动重跑)
./gradlew test --continuous
For advanced examples including TestContainers integration, GitHub Actions with coverage reports, and CI coverage verification, see [references/advanced-examples.md](references/advanced-examples.md)../gradlew test --continuous
如需包含TestContainers集成、GitHub Actions覆盖率报告、CI覆盖率验证等高级示例,请查看[references/advanced-examples.md](references/advanced-examples.md)。Commands Reference
命令参考
See references/commands-and-troubleshooting.md for complete command reference and troubleshooting guide.
完整的命令参考与故障排除指南请查看references/commands-and-troubleshooting.md。
See Also
相关链接
- gradle-spring-boot-integration - Spring Boot test starters
- gradle-performance-optimization - Parallel test execution
- gradle-ci-cd-integration - CI/CD test reporting
- JUnit 5 Documentation
- TestContainers Documentation
- gradle-spring-boot-integration - Spring Boot测试启动器
- gradle-performance-optimization - 并行测试执行
- gradle-ci-cd-integration - CI/CD测试报告
- JUnit 5 官方文档
- TestContainers 官方文档