JUnit 是由 Erich Gamma 與 Kent Beck 開發的回歸測試框架,屬於白箱測試(程式設計師測試)。核心用法:繼承 TestCase、以 testXXX() 命名測試方法、引入 junit.framework.*。
// 被測類
public class MathTool {
public static int gcd(int a, int b) {
int r;
while (b != 0) { r = a % b; a = b; b = r; }
return a;
}
}
// 測試類
public class MathToolTest extends TestCase {
public MathToolTest(String name) { super(name); }
public void testGcd() { assertEquals(5, MathTool.gcd(10, 5)); }
}
@Test
public void testBizException() {
try {
Password.validate("123");
fail("No exception thrown."); // 關鍵:無異常時測試必須失敗
} catch (Exception ex) {
assertTrue(ex instanceof BizException);
assertTrue(ex.getMessage().contains("error"));
}
}
痛點:
fail() 導致漏測@Test(expected)@Test(expected = BizException.class)
public void testBizException() {
Password.validate(null);
}
優點:簡潔、可讀性高、框架層面保證異常拋出。
限制:僅能驗證異常類別,無法檢查異常訊息內容。
@Rule ExpectedException (JUnit 4.7+)@Rule
public ExpectedException expectedEx = ExpectedException.none();
@Test
public void testBizException() throws InvalidPasswordException {
expectedEx.expect(BizException.class); // 驗證異常類別
expectedEx.expectMessage("required"); // 驗證訊息包含子字串
// expectedEx.expectMessage(Matcher matcher); // 或使用 Hamcrest Matcher 正則
Password.validate("");
}
ExpectedException 欄位必須為 public 且標註 @Rule@Test(expected=...) 與 expectedEx.expect...(),會衝突expectMessage() 參數支援 Matcher (正則) 或 String (子字串)| 方案 | 無異常時 | 異常類別錯誤 | 異常訊息不符 |
|---|---|---|---|
| try-catch | AssertionError: No exception thrown. | AssertionError 無具體上下文 | |
@Test(expected) | AssertionError: Expected exception: cc.test.BizException | ||
@Rule ExpectedException | Expected: (exception with message a string containing "YES. required" and an instance of BizException) got: [實際異常詳情] | ||
結論:@Rule ExpectedException 提供最豐富的失敗上下文,包含期望異常型別、期望訊息模式、實際獲得異常型別與訊息,極大提升除錯效率。
// 業務邏輯
public void validate(String pwd) {
if (pwd.length() < 6) throw new BizException("Password must contains at least 6 letters.");
if (pwd.length() > 15) throw new BizException("Password length less than 15 letters");
}
// 測試案例
@Test
public void testTooShort() {
expectedEx.expect(BizException.class);
expectedEx.expectMessage("at least 6");
Password.validate("123");
}
@Test
public void testTooLong() {
expectedEx.expect(BizException.class);
expectedEx.expectMessage("less than 15");
Password.validate("1234567890123456");
}
@Test(expected = XxxException.class)@Rule ExpectedException + expectMessage()CoreMatchers.containsString()、matchesPattern()testMethodName_Condition_ExpectedException 格式提升可讀性// JUnit 5 原生支援異常斷言,無需 Rule
assertThrows(BizException.class, () -> Password.validate(""),
"應拋出 BizException");
assertThrows(BizException.class, () -> Password.validate(""),
e -> assertTrue(e.getMessage().contains("required")));
若專案已升級 JUnit 5,建議直接使用 org.junit.jupiter.api.Assertions.assertThrows,API 更直觀且無 Rule 機制負擔。