后端单元测试基础
Forge 后端测试基于 JUnit 5 + Mockito。你需要掌握 Service 层测试(Mock Mapper)和 Controller 层测试(MockMvc)。
依赖
测试依赖在 forge-starter-test 或各模块 pom.xml 中已配置:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>Service 层测试
Service 层测试 Mock Mapper,不连接数据库:
java
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
@Mock
private OrderMapper orderMapper;
@InjectMocks
private OrderServiceImpl orderService;
@Test
void shouldCreateOrderSuccessfully() {
// 准备
OrderDTO dto = new OrderDTO();
dto.setOrderNo("ORD001");
dto.setAmount(10000L);
dto.setStatus("0");
when(orderMapper.selectByOrderNo("ORD001")).thenReturn(null);
when(orderMapper.insert(any(OrderEntity.class))).thenReturn(1);
// 执行
OrderVO result = orderService.create(dto);
// 验证
assertNotNull(result);
assertEquals("ORD001", result.getOrderNo());
verify(orderMapper).insert(any(OrderEntity.class));
}
@Test
void shouldThrowWhenOrderNoExists() {
OrderDTO dto = new OrderDTO();
dto.setOrderNo("ORD001");
OrderEntity existing = new OrderEntity();
existing.setOrderNo("ORD001");
when(orderMapper.selectByOrderNo("ORD001")).thenReturn(existing);
// 验证抛出异常
BusinessException ex = assertThrows(
BusinessException.class,
() -> orderService.create(dto)
);
assertEquals("订单号已存在", ex.getMessage());
}
}Controller 层测试
Controller 层测试使用 MockMvc:
java
@SpringBootTest
@AutoConfigureMockMvc
class OrderControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private OrderService orderService;
@Test
void shouldReturnPageResult() throws Exception {
// 准备
PageResult<OrderVO> pageResult = new PageResult<>();
pageResult.setTotal(1L);
pageResult.setList(List.of(new OrderVO()));
when(orderService.page(any(), eq(1), eq(10)))
.thenReturn(pageResult);
// 执行
mockMvc.perform(get("/biz/order/page")
.param("pageNum", "1")
.param("pageSize", "10")
.header("Authorization", "Bearer test-token"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data.total").value(1));
}
@Test
void shouldReturn400WhenOrderNoBlank() throws Exception {
OrderDTO dto = new OrderDTO();
// orderNo 为空
mockMvc.perform(post("/biz/order")
.contentType(MediaType.APPLICATION_JSON)
.content("{}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(400));
}
}测试命名
使用 should + 期望结果 + When + 条件 格式:
java
@Test
void shouldThrowWhenAmountIsZero() { ... }
@Test
void shouldReturnOrderWhenIdExists() { ... }
@Test
void shouldReturnEmptyWhenNoData() { ... }测试结构(AAA 模式)
java
@Test
void shouldUpdateOrderStatus() {
// Arrange(准备)
OrderEntity entity = new OrderEntity();
entity.setId(1L);
entity.setStatus("0");
when(orderMapper.selectById(1L)).thenReturn(entity);
// Act(执行)
orderService.updateStatus(1L, "1");
// Assert(验证)
verify(orderMapper).updateById(argThat(e -> "1".equals(e.getStatus())));
}运行测试
bash
# 运行全部测试
cd forge-server && mvn test
# 运行指定类
mvn test -Dtest=OrderServiceTest
# 运行指定方法
mvn test -Dtest=OrderServiceTest#shouldCreateOrderSuccessfully测试原则
| 原则 | 说明 |
|---|---|
| 独立性 | 测试之间不依赖执行顺序 |
| 可重复 | 多次执行结果一致 |
| 快速 | 单元测试不连接数据库 |
| 只测公共方法 | 不测试 private 方法 |
| Mock 外部依赖 | Service 测试 Mock Mapper |
