如何使用JUnit来测试某些代码是否抛出异常?

我当然可以这样做:

@Test
public void testFooThrowsIndexOutOfBoundsException() {
  boolean thrown = false;

  try {
    foo.doStuff();
  } catch (IndexOutOfBoundsException e) {
    thrown = true;
  }

  assertTrue(thrown);
}

我记得,对于这类情况,有一个注释或Assert.xyz之类的东西远没有JUnit那么笨拙,更符合JUnit的精神。


当前回答

在JUnit 4或更高版本中,您可以如下测试异常

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

这提供了许多可以用来改进JUnit测试的特性。如果您看到下面的示例,我将测试异常的3个方面。

引发的异常类型异常消息异常的原因

public class MyTest {

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

    ClassUnderTest classUnderTest;

    @Before
    public void setUp() throws Exception {
        classUnderTest = new ClassUnderTest();
    }

    @Test
    public void testAppleisSweetAndRed() throws Exception {

        exceptions.expect(Exception.class);
        exceptions.expectMessage("this is the exception message");
        exceptions.expectCause(Matchers.<Throwable>equalTo(exceptionCause));

        classUnderTest.methodUnderTest("param1", "param2");
    }

}

其他回答

除了NamShubWriter所说的,还要确保:

ExpectedException实例是公共的(相关问题)ExpectedException未在@Before方法中实例化。这篇文章清楚地解释了JUnit执行顺序的所有复杂性。

不要这样做:

@Rule    
public ExpectedException expectedException;

@Before
public void setup()
{
    expectedException = ExpectedException.none();
}

最后,这篇博客文章清楚地说明了如何断言抛出了某个异常。

在junit中,有四种方法可以测试异常。

六月5.x

对于junit5.x,可以使用assertThrows,如下所示@测试public void testFooThrowsIndexOutOfBoundsException(){抛出异常=assertThrows(IndexOutOfBoundsException.class,()->foo.doStuff());assertEquals(“预期消息”,exception.getMessage());}

六月4.x

对于junit4.x,使用测试注释的可选“expected”属性@测试(应为IndexOutOfBoundsException.class)public void testFooThrowsIndexOutOfBoundsException(){foo.doStuff();}对于junit4.x,请使用ExpectedException规则公共类XxxTest{@规则引发了public ExpectedException=ExpectedException.none();@测试public void testFooThrowsIndexOutOfBoundsException(){引发.预期(IndexOutOfBoundsException.class)//您可以像这样测试异常消息抛出.expectMessage(“预期消息”);foo.doStuff();}}您还可以使用junit3框架下广泛使用的经典try/catch方法@测试public void testFooThrowsIndexOutOfBoundsException(){尝试{foo.doStuff();fail(“未发生预期的异常。”);}catch(IndexOutOfBoundsException e){//如果执行到达这里,//它表示发生了此异常。//所以我们不需要处理它。}}所以如果你喜欢junit 5,那么你应该喜欢第一个当您只想测试异常类型时,使用第二种方法当需要进一步测试异常消息时,使用前两个和后两个如果您使用junit 3,则首选第四个有关详细信息,您可以阅读本文档和junit5用户指南。

我在Mkyong博客中找到了Junit 4最灵活、最优雅的答案。它具有使用@Rule注释的try/catch的灵活性。我喜欢这种方法,因为您可以读取自定义异常的特定属性。

package com.mkyong;

import com.mkyong.examples.CustomerService;
import com.mkyong.examples.exception.NameNotFoundException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasProperty;

public class Exception3Test {

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

    @Test
    public void testNameNotFoundException() throws NameNotFoundException {

        //test specific type of exception
        thrown.expect(NameNotFoundException.class);

        //test message
        thrown.expectMessage(is("Name is empty!"));

        //test detail
        thrown.expect(hasProperty("errCode"));  //make sure getters n setters are defined.
        thrown.expect(hasProperty("errCode", is(666)));

        CustomerService cust = new CustomerService();
        cust.findByName("");

    }

}

更新:JUnit5对异常测试进行了改进:assertThrows。

以下示例来自:Junit 5用户指南

import static org.junit.jupiter.api.Assertions.assertThrows;

@Test
void exceptionTesting() {
    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
        throw new IllegalArgumentException("a message");
    });
    assertEquals("a message", exception.getMessage());
}

使用JUnit 4的原始答案。

有几种方法可以测试是否引发异常。在我的文章《如何用JUnit编写优秀的单元测试》中,我还讨论了以下选项

设置预期参数@Test(预期=FileNotFoundException.class)。

@Test(expected = FileNotFoundException.class) 
public void testReadFile() { 
    myClass.readFile("test.txt");
}

使用try-catch

public void testReadFile() { 
    try {
        myClass.readFile("test.txt");
        fail("Expected a FileNotFoundException to be thrown");
    } catch (FileNotFoundException e) {
        assertThat(e.getMessage(), is("The file test.txt does not exist!"));
    }
     
}

使用ExpectedException规则进行测试。

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

@Test
public void testReadFile() throws FileNotFoundException {
    
    thrown.expect(FileNotFoundException.class);
    thrown.expectMessage(startsWith("The file test.txt"));
    myClass.readFile("test.txt");
}

您可以在JUnit4 wiki中阅读有关异常测试的更多信息,了解异常测试和bad.robot-Expected exceptions JUnit Rule。

您也可以这样做:

@Test
public void testFooThrowsIndexOutOfBoundsException() {
    try {
        foo.doStuff();
        assert false;
    } catch (IndexOutOfBoundsException e) {
        assert true;
    }
}