【測試之道】深刻探索:單元測試之異常測試

相關文章

預期異常

若是咱們測試知道這個方法是要拋出異常纔是咱們所指望的,否則就是測試失敗,咱們要如何驗證呢?驗證碼完成一般是重要的,可是確保代碼在特殊狀況下的行爲(如:異常,狀態,超時,etc)一樣重要。 舉個例子:java

new ArrayList<Object>().get(0);

這無疑無拋出IndexOutOfBoundsException,簡稱IOOBE。在@Test註解中,存在一個excepted參數,能夠知道方法會拋出咱們預期的異常。若是咱們想去驗證ArraryList 拋出正確的異常,咱們能夠這樣寫:單元測試

@Test(expected = IndexOutOfBoundsException.class) 
public void empty() { 
     new ArrayList<Object>().get(0); 
}

這個excepted 參數應該是咱們所應該關心的,若是這個執行方法拋出IOOBE,那麼這個方法將會經過測試。是否是用起來很簡單,很爽。然而,這個方法並非如理想中那麼簡單,萬能的。其實官方推薦的是使用 ExceptedException rule, 來實現。測試

下面我舉一個比較極端的一個例子吧! 若是我要測試一個方法,我碰見他會是超時的,終會拋出超時異常: 咱們能夠這樣寫:ui

@Test(timeout = 1000,expected = TestTimedOutException.class)
    public void testA() {
        System.out.println("first");
        for (;;){}// 必然會拋出超時異常
    }

我預測,他終會拋出異常超時,可是它仍然是沒法經過測試的,這樣的狀況咱們要如何作呢? 好吧,咱們就試試project B, 按照官方推薦的試試:this

@Rule
    public ExpectedException thrown = ExpectedException.none();
    @Test(timeout = 1000)
    public void testB() {
        thrown.expect(TestTimedOutException.class);
        for(;;){}
    }

這樣就能無缺的經過測試。固然,@Test(timeout=1000) 也是能夠用** @Rule public Timeout globalTimeout = Timeout.seconds(1000); ** 來替代的,後面會講到,你們耐心一點哈!.net

深刻探索異常測試(使用@Rule)

上面的方法對簡單的狀況頗有用,但也有它的侷限性。例如,您不能在異常中測試消息的值,或者在拋出異常後對域對象的狀態進行測試(如訂單業務的 下單狀態、支付狀態、退款狀態這種比較常見),etc。rest

Try/Catch 實現

在JUnit3.x 是經過 Try/Catch 來實現的code

@Test
public void testExceptionMessage() {
    try {
        new ArrayList<Object>().get(0);
        fail("Expected an IndexOutOfBoundsException to be thrown");
    } catch (IndexOutOfBoundsException anIndexOutOfBoundsException) {
        assertThat(anIndexOutOfBoundsException.getMessage(), is("Index: 0, Size: 0"));
    }
}

ExpectedException Rule

另外,使用ExpectedException rule . 此規則不只能夠指示您指望的異常狀況,還能夠指示預期的異常消息:對象

@Rule
public ExpectedException thr = ExpectedException.none();

@Test
public void shouldTestExceptionMessage() throws IndexOutOfBoundsException {
    List<Object> list = new ArrayList<Object>();
    // 預測異常
    thr.expect(IndexOutOfBoundsException.class);
    thr.expectMessage("Index: 0, Size: 0");
    list.get(0); // execution will never get past this line
}

也可讓你的expectmessage使用匹配器,這使你在你的測試更多的靈活性。一個例子:blog

thrown.expectMessage(Matchers.containsString("Size: 0"));

引入匹配器,須要org.hamcrest 的jar 包。 此外,您可使用匹配檢查異常,若是它具備嵌入式狀態你想驗證。例如:

import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;

import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

public class TestExy {
    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Test
    public void shouldThrow() {
        TestThing testThing = new TestThing();
        thrown.expect(NotFoundException.class);
        thrown.expectMessage(startsWith("some Message"));
        thrown.expect(hasProperty("response", hasProperty("status", is(404))));
        testThing.chuck();
    }

    private class TestThing {
        public void chuck() {
            Response response = Response.status(Status.NOT_FOUND).entity("Resource not found").build();
            throw new NotFoundException("some Message", response);
        }
    }
}
相關文章
相關標籤/搜索