一键导入
testing
Unit and integration testing patterns for this Spring Boot 4.0 Kafka consumer project using JUnit Jupiter, Testcontainers 2.x, EmbeddedKafka, and MockMvc.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Unit and integration testing patterns for this Spring Boot 4.0 Kafka consumer project using JUnit Jupiter, Testcontainers 2.x, EmbeddedKafka, and MockMvc.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
REST controller patterns for this Spring Boot Kafka consumer project, including CRUD endpoints and companion integration tests.
Flyway migration patterns for schema changes in this Spring Boot Kafka consumer project.
Kafka consumer patterns for this Spring Boot project, including JSON deserialization, persistence, and integration testing.
基于 SOC 职业分类
| name | testing |
| description | Unit and integration testing patterns for this Spring Boot 4.0 Kafka consumer project using JUnit Jupiter, Testcontainers 2.x, EmbeddedKafka, and MockMvc. |
This project has three categories of tests, all under src/test/java/com/learnkafka/. There are no mocks — every test runs against real infrastructure (embedded Kafka broker, Testcontainers PostgreSQL).
| Component | Version | Notes |
|---|---|---|
| JUnit Jupiter | 6.x | Via spring-boot-starter-test (Spring Boot 4.0) |
| Spring Boot Test | 4.0.3 | @SpringBootTest, @AutoConfigureMockMvc |
| Testcontainers | 2.x | @ImportTestcontainers + @ServiceConnection (NOT the old @Testcontainers/@Container) |
| EmbeddedKafka | (managed) | @EmbeddedKafka from spring-kafka-test |
| MockMvc | (managed) | Import AutoConfigureMockMvc from org.springframework.boot.webmvc.test.autoconfigure (Spring Boot 4.0 package) |
| Jackson 3.x | (managed) | tools.jackson.databind.ObjectMapper (NOT com.fasterxml.jackson) for test JSON serialization |
build.gradle)testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa-test'
testImplementation 'org.springframework.boot:spring-boot-starter-kafka-test'
testImplementation 'org.springframework.boot:spring-boot-starter-validation-test'
testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test'
testImplementation 'org.springframework.boot:spring-boot-testcontainers'
testImplementation 'org.testcontainers:testcontainers-postgresql'
testImplementation 'org.springframework.boot:spring-boot-starter-flyway-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
File: src/test/resources/application.yml
server.port: 0 — random port to avoid conflicts.spring.flyway.clean-disabled: false — allow Flyway clean in tests.spring.jpa.hibernate.ddl-auto: none — Flyway owns the schema; never use create or update.spring.datasource.* — @ServiceConnection auto-wires JDBC URL/username/password from the Testcontainer.spring.kafka.consumer.auto-offset-reset: latest — overridden to earliest in Kafka integration tests via @TestPropertySource.consumer/)File: LibraryEventsConsumerIntegrationTest.java
Purpose: End-to-end test — produce to EmbeddedKafka → real consumer picks up → persists to Testcontainers PostgreSQL.
Annotations:
@SpringBootTest
@EmbeddedKafka(partitions = 1, topics = {"library-events"},
bootstrapServersProperty = "spring.kafka.consumer.bootstrap-servers")
@TestPropertySource(properties = {"spring.kafka.consumer.auto-offset-reset=earliest"})
@ImportTestcontainers
Key patterns:
@ServiceConnection static PostgreSQLContainer<?> for the database.@BeforeEach builds a KafkaTemplate<Integer, LibraryEventDto> using EmbeddedKafkaBroker.getBrokersAsString() with IntegerSerializer + JsonSerializer.kafkaTemplate.send(...).get(10, TimeUnit.SECONDS).waitForRecordCount(expectedCount, timeoutSeconds) that polls libraryEventRepository.count() until the async consumer has persisted the expected records.libraryEventRepository.findAll() and bookRepository.findAll().Template:
@Test
void consumeLibraryEvent_ADD_shouldPersistLibraryEventAndBook() throws Exception {
// given
BookDto bookDto = new BookDto(1, "Clean Code", "Robert C. Martin");
LibraryEventDto dto = new LibraryEventDto(null, LibraryEventType.ADD, bookDto);
// when — produce to embedded Kafka
kafkaTemplate.send("library-events", dto).get(10, TimeUnit.SECONDS);
// then — wait for async consumer
waitForRecordCount(1, 10);
List<LibraryEvent> events = libraryEventRepository.findAll();
assertEquals(1, events.size());
// ... assert fields, FK relationships, audit timestamps
}
service/)File: LibraryEventServiceIntegrationTest.java
Purpose: Test LibraryEventService.processEvent() directly — bypasses Kafka entirely, exercises DTO→Entity mapping and JPA persistence against real PostgreSQL.
Annotations:
@SpringBootTest
@ImportTestcontainers
Key patterns:
ConsumerRecord<Integer, LibraryEventDto> manually via a buildConsumerRecord() helper — no Kafka broker needed.libraryEventService.processEvent(consumerRecord) synchronously.LibraryEvent saved first (IDENTITY-generated ID), then Book saved with FK set.Helper:
private ConsumerRecord<Integer, LibraryEventDto> buildConsumerRecord(Integer key, LibraryEventDto value) {
return new ConsumerRecord<>(
"library-events", // topic
0, // partition
0L, // offset
key, // key (nullable)
value // value
);
}
Template:
@Test
void processEvent_ADD_shouldPersistLibraryEventAndBook() {
// given
BookDto bookDto = new BookDto(1, "Clean Code", "Robert C. Martin");
LibraryEventDto dto = new LibraryEventDto(null, LibraryEventType.ADD, bookDto);
ConsumerRecord<Integer, LibraryEventDto> record = buildConsumerRecord(null, dto);
// when
libraryEventService.processEvent(record);
// then
assertEquals(1, libraryEventRepository.count());
assertEquals(1, bookRepository.count());
// ... assert fields, FK, audit columns
}
controller/)File: BookControllerIntegrationTest.java
Purpose: Test BookController REST endpoints via MockMvc against real PostgreSQL.
Annotations:
@SpringBootTest
@AutoConfigureMockMvc // from org.springframework.boot.webmvc.test.autoconfigure
@ImportTestcontainers
Key patterns:
MockMvc (autowired) for HTTP assertions — status(), jsonPath(), content().tools.jackson.databind.ObjectMapper for JSON serialization in request bodies.@BeforeEach cleans bookRepository (child first due to FK).persistBookWithLibraryEvent() helper to set up test data that needs a LibraryEvent FK.Helper for test data setup:
private void persistBookWithLibraryEvent(Integer bookId, String bookName, String bookAuthor) {
LibraryEvent libraryEvent = new LibraryEvent(null, LibraryEventType.ADD, null);
LibraryEvent savedEvent = libraryEventRepository.save(libraryEvent);
Book book = new Book(bookId, bookName, bookAuthor);
book.setLibraryEvent(savedEvent);
bookRepository.save(book);
}
Template:
@Test
void getBookById_shouldReturnBook() throws Exception {
persistBookWithLibraryEvent(1, "Clean Code", "Robert C. Martin");
mockMvc.perform(get("/v1/books/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.bookId").value(1))
.andExpect(jsonPath("$.bookName").value("Clean Code"))
.andExpect(jsonPath("$.bookAuthor").value("Robert C. Martin"))
.andExpect(jsonPath("$.libraryEventId").isNotEmpty())
.andExpect(jsonPath("$.createdAt").isNotEmpty())
.andExpect(jsonPath("$.updatedAt").isNotEmpty());
}
@Test
void createBook_shouldPersistAndReturn201() throws Exception {
BookDto bookDto = new BookDto(10, "Domain-Driven Design", "Eric Evans");
mockMvc.perform(post("/v1/books")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(bookDto)))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.bookId").value(10))
.andExpect(jsonPath("$.bookName").value("Domain-Driven Design"));
}
@BeforeEach (not @AfterEach) — ensures a clean DB even if the previous test failed.bookRepository.deleteAll() then libraryEventRepository.deleteAll().@ImportTestcontainers (Spring Boot 4.0) — NOT the old @Testcontainers from TC 1.x.@ServiceConnection on the container field — NOT @DynamicPropertySource.static and use the typed PostgreSQLContainer (not GenericContainer).@ServiceConnection
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:latest");
assertEquals, assertNotNull, assertTrue, assertFalse) — no AssertJ or Hamcrest.MockMvcResultMatchers (status(), jsonPath(), content()).{ClassName}IntegrationTest.java{methodUnderTest}_{scenario}_{expectedBehavior}() — e.g., processEvent_ADD_shouldPersistLibraryEventAndBook().@EmbeddedKafka; service tests bypass Kafka by constructing ConsumerRecord directly.tools.jackson.databind.ObjectMapper — NOT com.fasterxml.jackson.databind.ObjectMapper../gradlew test # Run all tests (Docker must be running for Testcontainers)
./gradlew test --tests "com.learnkafka.service.LibraryEventServiceIntegrationTest" # Single class
./gradlew test --tests "*.BookControllerIntegrationTest.getBookById*" # Single method pattern
compose.yaml or start Kafka externally — tests are self-contained.docs/7_INTEGRATION_TESTING_WITH_TESTCONTAINERS.md for detailed Testcontainers 2.x setup, lifecycle, and troubleshooting.docs/5_CONSUMER_CONCEPTS_HANDS_ON.md for Kafka consumer concepts tested in the consumer integration test.