JUnit:使用Java 8和Lambda表达式测试异常
在JUnit中,有許多方法可以在測試代碼中測試異常,包括try-catch idiom JUnit @Rule和catch-exception庫。 從Java 8開始,我們還有另一種處理異常的方法:使用lambda表達式。 在這篇簡短的博客文章中,我將演示一個簡單的示例,說明如何利用Java 8和lambda表達式的功能來測試JUnit中的異常。
注意:撰寫此博客文章的動機是在catch-exception項目頁面上發布的消息:
Java 8的lambda表達式將使catch-exception冗余。 因此,該項目將不再維護
SUT –被測系統
我們將測試以下2類拋出的異常。
第一個:
class DummyService {public void someMethod() {throw new RuntimeException("Runtime exception occurred");}public void someOtherMethod() {throw new RuntimeException("Runtime exception occurred",new IllegalStateException("Illegal state"));} }第二個:
class DummyService2 {public DummyService2() throws Exception {throw new Exception("Constructor exception occurred");}public DummyService2(boolean dummyParam) throws Exception {throw new Exception("Constructor exception occurred");} }所需語法
我的目標是實現與catch-exception庫接近的語法:
package com.github.kolorobot.exceptions.java8;import org.junit.Test; import static com.github.kolorobot.exceptions.java8.ThrowableAssertion.assertThrown;public class Java8ExceptionsTest {@Testpublic void verifiesTypeAndMessage() {assertThrown(new DummyService()::someMethod) // method reference// assertions.isInstanceOf(RuntimeException.class).hasMessage("Runtime exception occurred").hasNoCause();}@Testpublic void verifiesCauseType() {assertThrown(() -> new DummyService().someOtherMethod(true)) // lambda expression// assertions.isInstanceOf(RuntimeException.class).hasMessage("Runtime exception occurred").hasCauseInstanceOf(IllegalStateException.class);}@Testpublic void verifiesCheckedExceptionThrownByDefaultConstructor() {assertThrown(DummyService2::new) // constructor reference// assertions.isInstanceOf(Exception.class).hasMessage("Constructor exception occurred");}@Testpublic void verifiesCheckedExceptionThrownConstructor() {assertThrown(() -> new DummyService2(true)) // lambda expression// assertions.isInstanceOf(Exception.class).hasMessage("Constructor exception occurred");}@Test(expected = ExceptionNotThrownAssertionError.class) // making test passpublic void failsWhenNoExceptionIsThrown() {// expected exception not thrownassertThrown(() -> System.out.println());} }注意:與catch-exception相比的優勢在于,我們將能夠測試引發異常的構造函數。
創建“圖書館”
合成糖
assertThrown是一個靜態工廠方法,它使用對捕獲的異常的引用來創建ThrowableAssertion的新實例。
package com.github.kolorobot.exceptions.java8;public class ThrowableAssertion {public static ThrowableAssertion assertThrown(ExceptionThrower exceptionThrower) {try {exceptionThrower.throwException();} catch (Throwable caught) {return new ThrowableAssertion(caught);}throw new ExceptionNotThrownAssertionError();}// other methods omitted for now }ExceptionThrower是一個@FunctionalInterface ,可以使用lambda表達式,方法引用或構造函數引用創建實例。 assertThrown接受ExceptionThrower將期望并準備處理異常。
@FunctionalInterface public interface ExceptionThrower {void throwException() throws Throwable; }斷言
最后,我們需要創建一些斷言,以便可以在測試代碼中驗證關于teste異常的解釋。 實際上, ThrowableAssertion是一種自定義斷言,為我們提供了一種有效地驗證所捕獲異常的方法。 在下面的代碼中,我使用了Hamcrest匹配器來創建斷言。 ThrowableAssertion類的完整來源:
package com.github.kolorobot.exceptions.java8;import org.hamcrest.Matchers; import org.junit.Assert;public class ThrowableAssertion {public static ThrowableAssertion assertThrown(ExceptionThrower exceptionThrower) {try {exceptionThrower.throwException();} catch (Throwable caught) {return new ThrowableAssertion(caught);}throw new ExceptionNotThrownAssertionError();}private final Throwable caught;public ThrowableAssertion(Throwable caught) {this.caught = caught;}public ThrowableAssertion isInstanceOf(Class<? extends Throwable> exceptionClass) {Assert.assertThat(caught, Matchers.isA((Class<Throwable>) exceptionClass));return this;}public ThrowableAssertion hasMessage(String expectedMessage) {Assert.assertThat(caught.getMessage(), Matchers.equalTo(expectedMessage));return this;}public ThrowableAssertion hasNoCause() {Assert.assertThat(caught.getCause(), Matchers.nullValue());return this;}public ThrowableAssertion hasCauseInstanceOf(Class<? extends Throwable> exceptionClass) {Assert.assertThat(caught.getCause(), Matchers.notNullValue());Assert.assertThat(caught.getCause(), Matchers.isA((Class<Throwable>) exceptionClass));return this;} }AssertJ實施
如果您使用AssertJ庫,則可以使用AssertJ輕松創建ThrowableAssertion AssertJ版本,它提供了許多org.assertj.core.api.ThrowableAssert斷言。 該類的實現比上面介紹的Hamcrest更簡單。
package com.github.kolorobot.exceptions.java8;import org.assertj.core.api.Assertions; import org.assertj.core.api.ThrowableAssert;public class AssertJThrowableAssert {public static ThrowableAssert assertThrown(ExceptionThrower exceptionThrower) {try {exceptionThrower.throwException();} catch (Throwable throwable) {return Assertions.assertThat(throwable);}throw new ExceptionNotThrownAssertionError();} }AssertJ的示例測試:
public class AssertJJava8ExceptionsTest {@Testpublic void verifiesTypeAndMessage() {assertThrown(new DummyService()::someMethod).isInstanceOf(RuntimeException.class).hasMessage("Runtime exception occurred").hasMessageStartingWith("Runtime").hasMessageEndingWith("occurred").hasMessageContaining("exception").hasNoCause();} }摘要
僅用幾行代碼,我們構建了非??岬拇a,可幫助我們在JUnit中測試異常,而無需任何其他庫。 這僅僅是一個開始。 利用Java 8和lambda表達式的強大功能!
資源資源
- GitHub上提供了本文的源代碼 (請看com.github.kolorobot.exceptions.java8包)
- 我的其他一些文章關于在JUnit中測試異常。 請看一看:
- 定制斷言
翻譯自: https://www.javacodegeeks.com/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html
總結
以上是生活随笔為你收集整理的JUnit:使用Java 8和Lambda表达式测试异常的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 拼多多先用后付怎么关闭
- 下一篇: 酸爽是什么意思 什么是酸爽