| name | new-test |
| description | 为已有聚合、Handler、Domain 模型或基础设施组件编写测试。当需要补充单元测试或集成测试时使用。 |
新增测试
前置阅读
ywf-ddd-common/docs/common-test.md(测试基础设施 + ArchUnit 规则)
ywf-ddd-common/common-ddd/src/test/(Fixture 模式参照)
.agents/rules/03-coding-conventions.md(命名规范)
测试分类与模板
A. Handler 单元测试(Mockito)
位置:src/test/java/.../application/{agg}/handler/{Action}{Agg}HandlerTest.java
@ExtendWith(MockitoExtension.class)
class PayOrderHandlerTest {
@Mock
private OrderRepository orderRepository;
@Mock
private OrderAssembler orderAssembler;
@InjectMocks
private PayOrderHandler handler;
@Test
void handle_shouldTransitionToPaid() {
Order order = new Order(UUID.randomUUID(), List.of(item), "customer-1");
when(orderRepository.findById(any())).thenReturn(Optional.of(order));
when(orderAssembler.toDTO(any())).thenReturn(new OrderDTO());
OrderDTO result = handler.handle(new PayOrderCommand(order.getId()));
assertThat(order.getStatus()).isEqualTo(OrderStatus.PAID);
verify(orderRepository).update(order);
}
@Test
void handle_shouldThrowWhenNotFound() {
when(orderRepository.findById(any())).thenReturn(Optional.empty());
assertThatThrownBy(() -> handler.handle(new PayOrderCommand(UUID.randomUUID())))
.isInstanceOf(BusinessException.class);
}
}
B. Domain 模型测试(纯 JUnit,无 Mock)
位置:src/test/java/.../domain/{agg}/model/{Agg}Test.java
class OrderTest {
@Test
void pay_shouldTransitionFromPendingToPaid() {
Order order = new Order(UUID.randomUUID(), List.of(item), "customer-1");
order.pay();
assertThat(order.getStatus()).isEqualTo(OrderStatus.PAID);
}
@Test
void pay_shouldThrowWhenNotPending() {
Order order = new Order(UUID.randomUUID(), List.of(item), "customer-1");
order.pay();
assertThatThrownBy(order::pay)
.isInstanceOf(BusinessException.class);
}
@Test
void validate_shouldThrowWhenItemsEmpty() {
Order order = new Order(UUID.randomUUID(), List.of(), "customer-1");
assertThatThrownBy(order::validate)
.isInstanceOf(BusinessException.class);
}
}
C. Converter 测试
位置:src/test/java/.../infrastructure/persistence/{ds}/{agg}/converter/{Agg}ConverterTest.java
class OrderConverterTest {
private final OrderConverter converter = new OrderConverter();
@Test
void toDomain_and_toPO_shouldRoundTrip() {
OrderPO po = buildOrderPO();
Order domain = converter.toDomain(po);
OrderPO result = converter.toPO(domain);
assertThat(result.getId()).isEqualTo(po.getId());
assertThat(result.getStatus()).isEqualTo(po.getStatus());
}
@Test
void toDomain_shouldThrowOnInvalidJson() {
OrderPO po = buildOrderPO();
po.setItems("invalid-json{{{");
assertThatThrownBy(() -> converter.toDomain(po))
.isInstanceOf(IllegalStateException.class);
}
}
D. 集成测试(@SpringBootTest)
位置:src/test/java/.../integration/{Feature}IntegrationTest.java
@SpringBootTest
@ActiveProfiles("test")
class OrderFlowIntegrationTest {
@Autowired
private OrderAppService orderAppService;
@Test
void placeOrder_then_payOrder_shouldSucceed() {
}
}
Fixture 模式
- 复用测试夹具工厂:参照
common-ddd/src/test/.../fixtures/OrderFixtures.java
- 每个测试模块可建立
fixtures/ 包存放共享测试数据
- Fixture 方法命名:
create{Agg}() / build{Agg}PO()
命名规范
| 类型 | 命名 | 示例 |
|---|
| 测试类 | {ClassName}Test | PayOrderHandlerTest |
| 测试方法 | {method}_should{Expected} | handle_shouldThrowWhenNotFound |
| Fixture | {Agg}Fixtures | OrderFixtures |
验证
文档同步
- 如新增了 Fixture 模式或测试基础设施,更新
ywf-ddd-common/docs/common-test.md