效能測試常被延遲至開發後期,導致上線後才發現瓶頸。JUnitPerf 是建立在 JUnit 之上的輕量級效能測試框架,運用裝飾器模式,讓現有單元測試秒變計時測試與負載測試,實現「早期、頻繁、自動化」的效能驗證。
fastFail=true 參數:超時立即中斷,不等測試跑完ConstantTimer(intervalMs):固定間隔啟動執行緒RandomTimer(minMs, maxMs):隨機間隔,更貼近真實流量public class WidgetDAOImplTest extends TestCase {
private WidgetDAO dao;
public void testCreate() throws Exception {
IWidget wdgt = new Widget();
wdgt.setWidgetId(1000);
wdgt.setPartNumber("12-34-BBD");
try {
this.dao.createWidget(wdgt);
} catch (CreateException e) {
fail("CreateException thrown creating a Widget");
}
}
protected void setUp() throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
this.dao = (WidgetDAO) context.getBean("widgetDAO");
}
}
// 1. 純計時測試:單次執行必須在 2 秒內完成
public static Test suite() {
long maxElapsedTime = 2000; // 2 秒
return new TimedTest(new WidgetDAOImplTest("testCreate"), maxElapsedTime);
}
// 2. 純負載測試:10 個用戶,每 100ms 啟動一個
public static Test suite() {
int users = 10;
Timer timer = new ConstantTimer(100);
return new LoadTest(new WidgetDAOImplTest("testCreate"), users, timer);
}
// 3. 組合裝飾:負載 + 計時 (每個執行緒 2 秒內必須完成,10 用戶每 100ms 啟動)
public static Test suite() {
int users = 10;
Timer timer = new ConstantTimer(100);
long maxElapsedTime = 2000;
return new TimedTest(
new LoadTest(new WidgetDAOImplTest("testCreate"), users, timer),
maxElapsedTime
);
}
JUnit 本身的 setUp()/tearDown()、TestRunner 架構都會帶來額外開銷。測試時間 = 業務邏輯時間 + Fixture 開銷。必須先建立基準線:
public class DBUnitSetUpBenchmarkTest extends DatabaseTestCase {
private WidgetDAO dao = null;
public void testNothing() {
// 故意空白,僅測量 setUp/tearDown 時間
}
protected IDatabaseConnection getConnection() throws Exception {
Class.forName("org.hsqldb.jdbcDriver");
Connection conn = DriverManager.getConnection("jdbc:hsqldb:hsql://127.0.0.1", "sa", "");
return new DatabaseConnection(conn);
}
protected IDataSet getDataSet() throws Exception {
return new FlatXmlDataSet(new File("test/conf/seed.xml"));
}
protected void setUp() throws Exception {
super.setUp(); // DbUnit 裝載種子資料
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
this.dao = (WidgetDAO) context.getBean("widgetDAO");
}
}
執行此測試得知 Fixture 耗時 (如 2.5 秒),後續所有效能門檻皆需 加上此基準值。
| 建議 | 說明 |
|---|---|
| 分類隔離 | 將 JUnitPerf 測試歸類為 perf 或 integration 群組,Maven/Gradle 配置排除於預設 test 階段 |
| CI 整合 | 僅在夜間建置、發布前驗證、效能基準比對時執行,不阻塞每次 Commit 的快速回饋 |
| 環境一致性 | 效能測試需在固定規格機器/容器執行,避免雜訊干擾 |
| 資料隔離 | 負載測試併發寫入需處理資料衝突 (唯一鍵、樂觀鎖),或使用獨立測試資料庫 |
| 結果視覺化 | 搭配 JUnitPerfReport 或自訂 Listener 輸出 HTML/CSV 報表,追蹤趨勢 |
| 工具 | 定位 | 特點 |
|---|---|---|
| JUnitPerf | 單元級微效能/回歸 | 輕量、JUnit 原生、裝飾器模式、適合 CI 閘門 |
| JMH (Java Microbenchmark Harness) | 納秒級微基準測試 | JDK 官方、JIT 預熱、死碼消除防護、科學級精度 |
| Gatling / k6 / JMeter | 系統級負載/壓力測試 | 高併發、協定支援完整、報表豐富、需獨立測試環境 |
| Spring Boot Test + Testcontainers | 整合測試 | 真實資料庫/中間件、啟動較慢、適合驗證完整鏈路 |
JUnitPerf 以極低門檻將效能驗證左移至開發早期。核心價值在於:
雖非專業負載測試工具替代品,但作為「開發階段效能回歸防線」極具價值。建議搭配 JMH 驗證熱點方法微效能、Gatling 驗證系統級容量,構建多層次效能保障體系。