JUnit ExpectedException规则:超越基础
JUnit測試中有多種處理異常的方法。 正如我在以前的一篇文章中所寫的那樣 ,我最好的方法是使用org.junit.rules.ExpectedException規(guī)則。 基本上,規(guī)則是用org.junit.Before , org.junit.After , org.junit.BeforeClass或org.junit.AfterClass注釋的方法的替代(或補充),但它們功能更強大,并且功能更多。在項目和課程之間輕松共享。 在本文中,我將展示org.junit.rules.ExpectedException規(guī)則的更高級用法。
驗證異常消息
標準JUnit的org.junit.Test批注提供了expected屬性,該屬性允許您指定Throwable以在測試方法拋出指定類的異常時導致測試方法成功。 在許多情況下,這似乎足夠了,但是如果您要驗證異常消息,則必須找到其他方法。 使用ExpectedException非常簡單:
public class ExpectedExceptionsTest {@Rulepublic ExpectedException thrown = ExpectedException.none();@Testpublic void verifiesTypeAndMessage() {thrown.expect(RuntimeException.class);thrown.expectMessage("Runtime exception occurred");throw new RuntimeException("Runtime exception occurred");} }在上面的代碼片段中,我們希望消息contains給定的子字符串。 僅與類型檢查相比,它更安全。 為什么? 假設我們有一個ExceptionThrower ,如下所示:
class ExceptionsThrower {void throwRuntimeException(int i) {if (i <= 0) {throw new RuntimeException("Illegal argument: i must be <= 0");}throw new RuntimeException("Runtime exception occurred");} }如您所見,方法拋出的兩個異常均為RuntimeException ,因此,如果我們不檢查消息,則不能100%地確定方法會拋出哪個異常。 以下測試將通過:
@Test public void runtimeExceptionOccurs() {thrown.expect(RuntimeException.class);// opposite to expectedexceptionsThrower.throwRuntimeException(0); }@Test public void illegalArgumentExceptionOccurs() {thrown.expect(RuntimeException.class);// opposite to expectedexceptionsThrower.throwRuntimeException(1); }檢查異常中的消息將解決問題,并確保您正在驗證所需的異常。 與@Test注釋的方法的expected屬性相比,這已經(jīng)是一個優(yōu)勢。
但是,如果您需要以更復雜的方式驗證異常消息怎么辦? ExpectedException通過提供Hamcrest匹配器為expectMessage方法(而不是字符串)允許您這樣做。 讓我們看下面的例子:
@Test public void verifiesMessageStartsWith() {thrown.expect(RuntimeException.class);thrown.expectMessage(startsWith("Illegal argument:"));throw new RuntimeException("Illegal argument: i must be <= 0"); }如您所料,您可以提供自己的匹配器,以驗證消息。 讓我們來看一個例子。
@Test public void verifiesMessageMatchesPattern() {thrown.expect(RuntimeException.class);thrown.expectMessage(new MatchesPattern("[Ii]llegal .*"));throw new RuntimeException("Illegal argument: i must be <= 0"); }class MatchesPattern extends TypeSafeMatcher<String> {private String pattern;public MatchesPattern(String pattern) {this.pattern = pattern;}@Overrideprotected boolean matchesSafely(String item) {return item.matches(pattern);}@Overridepublic void describeTo(Description description) {description.appendText("matches pattern ").appendValue(pattern);}@Overrideprotected void describeMismatchSafely(String item, Description mismatchDescription) {mismatchDescription.appendText("does not match");} }驗證異常對象
在某些情況下,匹配消息可能還不夠。 自定義方法可能會有例外,您也想對其進行驗證。 沒問題 ExpectedException允許以expect方法,它匹配。
@Test public void verifiesCustomException() {thrown.expect(RuntimeException.class);thrown.expect(new ExceptionCodeMatches(1));throw new CustomException(1); }class CustomException extends RuntimeException {private final int code;public CustomException(int code) {this.code = code;}public int getCode() {return code;} }class ExceptionCodeMatches extends TypeSafeMatcher<CustomException> {private int code;public ExceptionCodeMatches(int code) {this.code = code;}@Overrideprotected boolean matchesSafely(CustomException item) {return item.getCode() == code;}@Overridepublic void describeTo(Description description) {description.appendText("expects code ").appendValue(code);}@Overrideprotected void describeMismatchSafely(CustomException item, Description mismatchDescription) {mismatchDescription.appendText("was ").appendValue(item.getCode());} }請注意,我同時實現(xiàn)了TypeSafeMatcher describeTo和describeMismatchSafely方法。 當測試失敗時,我需要它們產(chǎn)生看起來很漂亮的錯誤消息。 看下面的例子:
java.lang.AssertionError: Expected: (an instance of java.lang.RuntimeException and expects code <1>)but: expects code <1> was <2>檢查原因
您可以使用ExpectedException做的另一件事是驗證引發(fā)異常的原因。 這也可以使用自定義匹配器完成:
@Test public void verifiesCauseTypeAndAMessage() {thrown.expect(RuntimeException.class);thrown.expectCause(new CauseMatcher(IllegalStateException.class, "Illegal state"));throw new RuntimeException("Runtime exception occurred",new IllegalStateException("Illegal state")); }private static class CauseMatcher extends TypeSafeMatcher<Throwable> {private final Class<? extends Throwable> type;private final String expectedMessage;public CauseMatcher(Class<? extends Throwable> type, String expectedMessage) {this.type = type;this.expectedMessage = expectedMessage;}@Overrideprotected boolean matchesSafely(Throwable item) {return item.getClass().isAssignableFrom(type)&& item.getMessage().contains(expectedMessage);}@Overridepublic void describeTo(Description description) {description.appendText("expects type ").appendValue(type).appendText(" and a message ").appendValue(expectedMessage);} }摘要
ExpectedException規(guī)則是一個強大的功能。 通過添加Hamcrest匹配器,您可以輕松地為異常測試創(chuàng)建健壯且可重用的代碼。
- 可以在GitHub上找到代碼示例。 還請檢查我以前的文章: JUnit中處理異常的3種方法。 選擇哪一個?
翻譯自: https://www.javacodegeeks.com/2014/03/junit-expectedexception-rule-beyond-basics.html
總結
以上是生活随笔為你收集整理的JUnit ExpectedException规则:超越基础的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 邮件怎么设置自动回复(邮件设置自动回复本
- 下一篇: 如何将IntelliJ项目添加到GitH