DDD testing strategy — from value object unit tests to end-to-end validation across all DDD architectures. Covers the DDD test pyramid, layer-specific test patterns, mock strategies by architecture, Test-Driven Domain Design (TDDD), CI/CD pipeline integration, and N+1 query detection.
Workflow
用户输入 → 场景分类 → 输出测试策略 + 代码模板
Step 1: Classify by user question scenario (Pyramid/AR/Repository/Mock/CQRS/TDDD/CI-CD/Coverage) Step 2: Get the corresponding test template from references Step 3: Adjust Mock strategy by architecture type Step 4: Output code template + CI/CD configuration + coverage target
什么时候用:用户询问 DDD 测试策略、聚合根测试、Repository 测试、Mock 策略、CQRS 测试、TDDD、CI/CD 测试集成时触发。
## Boundary
### ✅ 擅长处理
1. DDD 测试金字塔(60% Domain + 20% Integration + 10% E2E + 10% Architecture)
2. 各层测试策略:Value Object / Aggregate Root / Domain Service / Repository / Application / Adapter
3. 按架构类型差异化测试(Layered / Hexagonal / Clean / COLA / CQRS / Event Sourcing)
4. 测试驱动领域设计(TDDD)方法论
5. Mock 策略选择(Mock Ports / Capture Events / Real DB)
6. CI/CD 三阶段流水线 + N+1 查询检测 + ArchUnit 架构测试
7. 测试覆盖率目标设定 + 分支覆盖率检查
### ⚠️ 需要条件
1. 已有 DDD 项目代码或正在设计领域模型
2. 已有测试框架(JUnit / Mockito / Spring Test / Testcontainers)
3. 理解 DDD 战术模式(Entity / VO / Aggregate / Repository / Domain Event)
### ❌ 超出范围(不适用场景)
1. 非 DDD 项目测试 — 标准测试框架(JUnit / pytest / Jest)
2. 纯前端测试 — Cypress / Playwright / Vitest
3. 性能 / 负载 / 安全测试 — JMeter / k6 / OWASP ZAP
4. 语言特定测试教程 — 概念和模式语言无关
5. 非 DDD 项目的 CI/CD 配置
## Audience
This skill is designed for: **Backend developers** (implementing DDD architectures), **Software architects** (evaluating and selecting patterns), **Tech leads** (reviewing team implementations), and **DDD beginners** (learning domain-driven design fundamentals).
## Rules
1. DDD test pyramid must prioritize Domain layer testing (60% of total tests).
2. Domain layer tests must never mock Domain Services or Aggregate Roots — only mock external ports.
3. Repository integration tests must use Testcontainers with real databases, never mocks.
4. Event Sourcing projects must include event replay and projection tests.
5. Architecture compliance tests (ArchUnit) must run in CI pipeline.
## DDD 测试金字塔
DDD 金字塔与经典金字塔的关键区别:Domain 层(VO + AR + DS)占 **60%**,是测试核心。
╱ E2E Tests ╲ ← 10%
╱──────── API Integration ────────╲ ← 10%
╱────── Repository Integration ──────╲ ← 10%
╱─────── Application Service ─────────╲ ← 10%
╱──────── Domain Service Tests ──────────╲ ← 15%
╱────────── Aggregate Root Tests ───────────╲ ← 25%
╱──────────── Value Object Tests ──────────────╲ ← 15%
## 各层测试策略
### ① Value Object 测试(纯函数)
```java
@Test void money_should_prevent_negative_amount() {
assertThrows(IllegalArgumentException.class, () -> new Money(-1.0, "CNY")); }
@Test void money_add_should_sum_same_currency() {
assertEquals(new Money(30.0, "CNY"), new Money(10.0, "CNY").add(new Money(20.0, "CNY"))); }
Coverage: construction validation, operation logic, equality comparison, invariants.
② Aggregate Root testing (core business logic)
class OrderPayTest {
@Test void pay_changes_status_to_paid_when_draft() { ... }
@Test void pay_emits_orderPaidEvent() { ... }
@Test void pay_fails_when_already_paid() { ... }
@Test void pay_fails_when_cancelled() { ... } }
Coverage: independent test class for each state transition → happy path + boundary conditions + invariants + events.
③ Domain Service testing (Mock Repository, Capture Event)
@Test void pricing_service_applies_vip_discount() {
when(orderRepository.findById(order.getId())).thenReturn(Optional.of(order));
pricingService.calculatePrice(order.getId());
assertEquals(new Money(90.0, "CNY"), order.getTotalAmount()); }
Mock principle: Mock only Repository / Gateway (Interface), do not Mock Domain Service or Aggregate Root.
④ Application Service + ⑤ Repository + ⑥ Adapter testing
@Test void place_order_creates_and_saves() {
var orderId = handler.handle(new PlaceOrderCommand("cust-123", ...));
assertNotNull(orderId); }
@SpringBootTest @Testcontainers
class OrderRepositoryImplTest {
@Test void persists_and_retrieves_complete_aggregate() { ... } }
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class OrderControllerTest {
@Test void post_orders_returns_201() { ... }
@Test void post_invalid_product_returns_400() { ... } }
App Service: Mock all external ports. Repository: Testcontainers + real DB. Adapter: MockMvc + real DB.
Mock strategy matrix
| Test target | Repository | Gateway | EventBus | External |
|---|---|---|---|---|
| Value Object | N/A | N/A | N/A | N/A |
| Aggregate Root | N/A | N/A | Capture | N/A |
| Domain Service | Mock | Mock | Capture | Mock |
| Application Service | Mock | Mock | Mock | Mock |
| Repository Integration | Real DB | N/A | N/A | N/A |
| API Integration | Real DB | Mock | Mock | Mock |
| E2E | Real DB | Real | Real | Real |
| Principle: Domain layer does not need Mock; Mock only interfaces (Ports), do not Mock implementation classes; use Capture pattern for domain events. |
Testing differences across architectures
| Architecture | Testing focus | Difference description |
|---|---|---|
| Layered | Aggregate Root + Repository | Full testing of Domain layer (60%+) |
| Hexagonal | Port Mock + Adapter Integration | Mocking the interface means mocking the entire external |
| Clean | Entity + UseCase Interactor | Mock output ports at the UseCase layer |
| COLA | Domain + App Service | Domain has zero dependencies; additionally test CQRS separation |
| CQRS | Command + Query Read Model | Use aggregate testing for write model; query views directly for read model |
| Event Sourcing | Event Replay + Projection | Aggregate replay testing (mandatory); projection read model testing |
Test-Driven Domain Design(TDDD)
Four-step workflow: RED → GREEN → REFACTOR → REPEAT
@Test void tddd_order_should_not_allow_paying_twice() {
Order order = Order.create(customerId, items);
order.pay(mockGateway);
assertThrows(OrderException.class, () -> order.pay(mockGateway)); }
public void pay(PaymentGateway gateway) {
if (this.status == OrderStatus.PAID) throw new OrderException("Already paid");
this.status = OrderStatus.PAID;
addDomainEvent(new OrderPaidEvent(this.getId())); }
Test coverage targets
| Layer | Target | Key coverage points |
|---|---|---|
| Value Object | ≥ 95% | Construction validation, operation logic, equality comparison |
| Aggregate Root | ≥ 95% | State transitions (every path), domain events |
| Domain Service | ≥ 90% | Cross-entity orchestration, external data computation |
| Application | ≥ 80% | Use Case full path + exception paths |
| Repository | ≥ 80% | Aggregate integrity, N+1 queries |
| Adapter (API) | ≥ 70% | Protocol conversion, error mapping |
| Recommend prioritizing trackingbranch coverage, Domain layer ≥ 90%. |
Gotchas — common pitfalls
- Testing only App Service and not Domain — The core of DDD is the Domain layer.
- Mocking Domain Service — Domain Service should not be mocked.
- Testing only the Happy Path for aggregate roots — Invariant violations and boundary conditions must be covered.
- Treating Repository tests as E2E — Repository only verifies persistence.
- Forgetting Event Replay testing — The most hidden source of bugs.
- Coupling tests to implementation — Test behavior, not internal details.
- Not testing domain events — Event publication should be verified for every business method.
- Mocking DB instead of using Testcontainers — Always use a real database.
- Not testing the Query side in CQRS — Command and Query side strategies are completely different.
- Not detecting N+1 queries — Integrate SQL count detection in CI.
- Too many E2E tests — Keep only 3-5 key journeys.
- Forget ArchUnit — Dependency direction compliance should be checked automatically.
FAQ
| Question | Answer |
|---|---|
| Do aggregate root tests need Spring? | No. Pure POJO, use JUnit + AssertJ directly. |
| Should Repository be mocked or use a real DB? | Use mocks for Domain Service; use a real DB for Repository. |
| How do you test the Query side of CQRS? | Access the read model directly; no mocking needed. |
| What is the essential test for Event Sourcing? | Event Replay: given an event sequence → replay → verify state. |
| How do you avoid N+1 queries? | Integrate SQLStatementCountValidator. |
| What is the difference between TDDD and traditional TDD? | TDDD uses "domain behavior/state transitions" as the unit. |
Keywords
DDD testing, test pyramid, aggregate root test, value object test, domain service test, repository test, application service test, adapter test, CQRS testing, Event Sourcing test, TDDD, mock strategy, Testcontainers, ArchUnit, N+1 test, domain event test, branch coverage, CI/CD testing, integration test, E2E test, event replay test
References
| File | Purpose |
|---|---|
| references/testing.md | Test pyramid + TypeScript examples for each layer |
| references/mock-integration-patterns.md | Mock implementation + Java integration testing |
| references/clean-ddd-hexagonal-testing.md | Clean/Hexagonal/DDD multi-layer testing |
| references/unit-testing-strategies.md | VO/AR/DS unit testing + state transitions |
| references/integration-test-strategies.md | Repository/API integration testing + N+1 |
| references/cqrs-event-sourcing-testing.md | CQRS + ES replay/projection/snapshot testing |
| references/test-coverage-targets.md | Coverage targets + branch coverage + JaCoCo |
| references/ci-cd-test-stages.md | Three-stage CI/CD + GitHub Actions |
| references/architecture-testing-comparison.md | Architecture-specific testing differences + project phase strategy |
| references/test-driven-domain-design.md | TDDD four-step workflow + complete case study |
Examples
| File | Purpose |
|---|---|
| examples/domain-test-examples.md | VO + AR + DS complete testing example |
| examples/app-adapter-test-examples.md | App Service + Adapter + E2E |
| examples/cqrs-es-test-examples.md | CQRS + ES replay/projection/snapshot testing |
| examples/builder-mock-patterns.md | Builder + Mock Repository/EventPublisher |
| examples/architecture-test-examples.md | ArchUnit architecture testing (layering/aggregate isolation) |
Security & Safety
This skill is pure documentation. It contains no executable scripts, collects no user data, accesses no external services or networks.
DDD Skills Journey
📍 You are here:
ddd-testing-strategist— Step 6 ← Previous: hand off toddd-domain-designerskill(Install:npx skills add full-stack-skills/ddd-skills --skill ddd-domain-designer). → Next: hand off toddd-devops-integrationskill(Install:npx skills add full-stack-skills/ddd-skills --skill ddd-devops-integration). 🔗 Related: hand off toddd-code-reviewerskill(Install:npx skills add full-stack-skills/ddd-skills --skill ddd-code-reviewer) |ddd-cqrs-architectureskill(Install:npx skills add full-stack-skills/ddd-skills --skill ddd-cqrs-architecture). 🏠 Home: hand off toddd-architecture-awesomeskill(Install:npx skills add full-stack-skills/ddd-skills --skill ddd-architecture-awesome).