使用JUnit來測試Java代碼中的異常有不少種方式,你知道幾種?java
給定這樣一個class。測試
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { if (age < 0 ) { throw new IllegalArgumentException("age is invalid"); } this.age = age; } } |
咱們來測試setAge方法。this
Try-catch 方式
1 2 3 4 5 6 7 8 9 10 11 |
@Test public void shouldGetExceptionWhenAgeLessThan0() { Person person = new Person(); try { person.setAge(-1); fail("should get IllegalArgumentException"); } catch (IllegalArgumentException ex) { assertThat(ex.getMessage(),containsString("age is invalid")); } } |
這是最容易想到的一種方式,可是太囉嗦。google
JUnit annotation方式
JUnit中提供了一個expected
的annotation來檢查異常。spa
1 2 3 4 5 6 |
@Test(expected = IllegalArgumentException.class) public void shouldGetExceptionWhenAgeLessThan0() { Person person = new Person(); person.setAge(-1); } |
這種方式看起來要簡潔多了,可是沒法檢查異常中的消息。rest
ExpectedException rule
JUnit7之後提供了一個叫作ExpectedException
的Rule來實現對異常的測試。code
1 2 3 4 5 6 7 8 9 10 11 12 |
@Rule public ExpectedException exception = ExpectedException.none(); @Test public void shouldGetExceptionWhenAgeLessThan0() { Person person = new Person(); exception.expect(IllegalArgumentException.class); exception.expectMessage(containsString("age is invalid")); person.setAge(-1); } |
這種方式既能夠檢查異常類型,也能夠驗證異常中的消息。xml
使用catch-exception庫
有個catch-exception庫也能夠實現對異常的測試。get
首先引用該庫。it
1 2 3 4 5 6 |
<dependency> <groupId>com.googlecode.catch-exception</groupId> <artifactId>catch-exception</artifactId> <version>1.2.0</version> <scope>test</scope> <!-- test scope to use it only in tests --> </dependency> |
而後這樣書寫測試。
1 2 3 4 5 6 7 8 |
@Test public void shouldGetExceptionWhenAgeLessThan0() { Person person = new Person(); catchException(person).setAge(-1); assertThat(caughtException(),instanceOf(IllegalArgumentException.class)); assertThat(caughtException().getMessage(), containsString("age is invalid")); } |
這樣的好處是能夠精準的驗證異常是被測方法拋出來的,而不是其它方法拋出來的。
catch-exception庫還提供了多種API來進行測試。
先加載fest-assertion庫。
1 2 3 4 5 |
<dependency> <groupId>org.easytesting</groupId> <artifactId>fest-assert-core</artifactId> <version>2.0M10</version> </dependency> |
而後能夠書寫BDD風格的測試。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Test public void shouldGetExceptionWhenAgeLessThan0() { // given Person person = new Person(); // when when(person).setAge(-1); // then then(caughtException()) .isInstanceOf(IllegalArgumentException.class) .hasMessage("age is invalid") .hasNoCause(); } |
若是喜歡Hamcrest風格的驗證風格的話,catch-exception也提供了相應的Matcher API。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Test public void shouldGetExceptionWhenAgeLessThan0() { // given Person person = new Person(); // when when(person).setAge(-1); // then assertThat(caughtException(), allOf( instanceOf(IllegalArgumentException.class) , hasMessage("age is invalid") ,hasNoCause())); } |
第一種最土鱉,第二種最簡潔,第四種最靠譜。