在Java中如何使用JUnit验证抛出的异常?

Iai*_*ain 28 java junit exception-handling exception

在为Java API编写单元测试时,可能会出现需要对异常执行更详细验证的情况.比JUnit 提供的@test注释提供的更多.

例如,考虑一个应该从其他接口捕获异常的类,包装该异常并抛出包装的异常.您可能需要验证:

  1. 抛出包装异常的确切方法调用.
  2. 包装器异常将原始异常作为其原因.
  3. 包装器异常的消息.

这里的要点是,您希望在单元测试中对异常进行额外验证(而不是关于是否应该验证异常消息等事项的争论).

对此有什么好的方法?

gue*_*rda 24

根据你的答案,这是一个很好的方法.除此之外:

您可以将函数包装expectException到一个名为的新Annotation中ExpectedException.
带注释的方法如下所示:

@Test
@ExpectedException(class=WrapperException.class, message="Exception Message", causeException)
public void testAnExceptionWrappingFunction() {
  //whatever you test
}
Run Code Online (Sandbox Code Playgroud)

这种方式更具可读性,但它的方法完全相同.

另一个原因是:我喜欢Annotations :)

  • 以这种方式,您必须扩展测试运行器,以便考虑@ExpectedException (2认同)

Jon*_*nas 21

在JUnit 4中,可以使用ExpectedException规则轻松完成.

以下是javadocs的示例:

// These tests all pass.
public static class HasExpectedException {
    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Test
    public void throwsNothing() {
        // no exception expected, none thrown: passes.
    }

    @Test
    public void throwsNullPointerException() {
        thrown.expect(NullPointerException.class);
        throw new NullPointerException();
    }

    @Test
    public void throwsNullPointerExceptionWithMessage() {
        thrown.expect(NullPointerException.class);
        thrown.expectMessage("happened?");
        thrown.expectMessage(startsWith("What"));
        throw new NullPointerException("What happened?");
    }
}
Run Code Online (Sandbox Code Playgroud)


aku*_*uhn 18

看看提出的答案,你真的可以感受到Java中没有闭包的痛苦.恕我直言,最可读的解决方案是你好老尝试赶上.

@Test
public void test() {
    ...
    ...
    try {
        ...
        fail("No exception caught :(");
    }
    catch (RuntimeException ex) {
        assertEquals(Whatever.class, ex.getCause().getClass());
        assertEquals("Message", ex.getMessage());
    }
}
Run Code Online (Sandbox Code Playgroud)


mP.*_*mP. 11

对于JUNIT 3.x

public void test(){
   boolean thrown = false;
   try{
      mightThrowEx();
   } catch ( Surprise expected ){
      thrown = true;
      assertEquals( "message", expected.getMessage());
   }
  assertTrue(thrown );
}
Run Code Online (Sandbox Code Playgroud)


Esk*_*sko 5

在这篇文章之前,我通过这样做完成了我的异常验证:

try {
    myObject.doThings();
    fail("Should've thrown SomeException!");
} catch (SomeException e) {
    assertEquals("something", e.getSomething());
}
Run Code Online (Sandbox Code Playgroud)

我花了一些时间考虑这个问题,并想出了以下内容(Java5,JUnit 3.x):

// Functor interface for exception assertion.
public interface AssertionContainer<T extends Throwable> {
    void invoke() throws T;
    void validate(T throwable);
    Class<T> getType();
}

// Actual assertion method.
public <T extends Throwable> void assertThrowsException(AssertionContainer<T> functor) {
    try {
        functor.invoke();
        fail("Should've thrown "+functor.getType()+"!");
    } catch (Throwable exc) {
        assertSame("Thrown exception was of the wrong type! Expected "+functor.getClass()+", actual "+exc.getType(),
                   exc.getClass(), functor.getType());
        functor.validate((T) exc);
    }
}

// Example implementation for servlet I used to actually test this. It was an inner class, actually.
AssertionContainer<ServletException> functor = new AssertionContainer<ServletException>() {
    public void invoke() throws ServletException {
        servlet.getRequiredParameter(request, "some_param");
    }

    public void validate(ServletException e) {
        assertEquals("Parameter \"some_param\" wasn't found!", e.getMessage());
    }

    public Class<ServletException> getType() {
        return ServletException.class;
    }
}

// And this is how it's used.
assertThrowsException(functor);
Run Code Online (Sandbox Code Playgroud)

看着这两个我无法决定哪一个我更喜欢.我想这是其中一个问题,其中实现目标(在我的情况下,使用functor参数的断言方法)从长远来看是不值得的,因为这样做6+代码来断言尝试要容易得多..catch块.

再说一次,也许我在星期五晚上解决问题的10分钟结果并不是最聪明的方法.


rwi*_*zel 5

@阿库恩:

即使没有闭包,我们也可以获得更具可读性的解决方案(使用catch-exception):

import static com.googlecode.catchexception.CatchException.*;

public void test() {
    ...
    ...
    catchException(nastyBoy).doNastyStuff();
    assertTrue(caughtException() instanceof WhateverException);
    assertEquals("Message", caughtException().getMessage());
}
Run Code Online (Sandbox Code Playgroud)