| 層級 | 測試重點 | 工具/策略 |
| Service 層 | 純業務邏輯:事務、計算、規則驗證 | JUnit + Mockito Mock Repository,核心測試目標 |
| Repository 層 | SQL 正確性、映射關係 | @DataJpaTest + Testcontainers 真實 DB |
| Controller 層 | 參數綁定、視圖解析、HTTP 狀態碼 | @WebMvcTest + MockMvc,薄測試 |
| E2E | 全鏈路:瀏覽器→Controller→Service→DB | Selenium / Cypress / Postman |
重構建議:把業務邏輯下沉到 Service
// 原 Controller 內聯邏輯
@Service
public class FeeBillClosedService {
@Transactional(readOnly = true)
public DataGrid list(FeeBillClosedEntity query, DataGrid grid) {
// 複雜 CriteriaQuery 組裝、多表關聯、數據轉換
// 單元測試只需 Mock systemService、feeBillClosedService
}
@Transactional
public void delete(String id) { ... }
}
Controller 變薄:
@RequestMapping(params = "datagrid")
public void datagrid(FeeBillClosedEntity q, DataGrid grid, HttpServletResponse resp) {
feeBillClosedService.list(q, grid); // 一行委派
TagUtil.datagrid(resp, grid);
}
Service 層單元測試範例
@RunWith(MockitoJUnitRunner.class)
public class FeeBillClosedServiceTest {
@Mock SystemService systemService;
@InjectMocks FeeBillClosedService service;
@Test
public void list_shouldEnrichComName() {
// Given
FeeBillClosedEntity entity = new FeeBillClosedEntity();
entity.setComFkid("c1");
DataGrid grid = new DataGrid();
grid.setResults(Arrays.asList(entity));
when(systemService.singleResult(anyString())).thenReturn(
new FeeComEntity().setContacts("張三").setPhone("13800000000"),
new EcommerceRecordEntity().setEcommerceName("測試公司")
);
// When
service.list(entity, grid);
// Then
assertEquals("測試公司", entity.getComName());
verify(systemService, times(1)).singleResult(contains("FeeComEntity"));
}
}
總結
別在 Controller 寫業務邏輯,別對 Controller 寫深度單元測試。 遵循「薄 Controller、厚 Service、可測試 Service」原則,JUnit 才能發揮最大價值。想測 HTTP 行為?上 MockMvc 做薄切面測試;想測全鏈路?寫 E2E 自動化腳本。
- 上一篇文章: Flex 調用 JavaScript 傳參報錯 #1032 堆棧溢位?參數類型不匹配是元兇
- 下一篇文章: C# 遠程連接 Informix 數據庫:連接字符串配置與客戶端設置全攻略
Copyright ©
程式碼之家 All Rights Reserved