JUnit 4 - 期望某个类的异常,但不是子类

时间:2013-11-15 17:20:57

标签: java junit

我会尝试提供一个陈腐,无用的例子来很好地减少问题: - )

我有一个GenericException,一个MoreSpecificException扩展了GenericException

我需要测试SomeService.doThis()是否会引发MoreSpecificException。 JUnit让我这样优雅。

@Test(expected = MoreSpecificException.class)
public void testDoThis() throws GenericException {
    new SomeService().doThis();
}

但是,我还需要测试SomeService.doThat()是否会引发GenericException,所以我试过了。

@Test(expected = GenericException.class)
public void testDoThat() throws GenericException {
    new SomeService().doThat();
}

然而,我发现如果doThat()实际上抛出MoreSpecificException,那么第二次测试仍会通过。我认为这是因为MoreSpecificException GenericException并且实施了注释以尊重该关系。

虽然这是一个合理的默认行为,我不想要这个。我想测试doThat()只引用GenericException引发GenericException。如果它抛出MoreSpecificExceptionGenericException的任何其他子类,我希望测试失败。

阅读docs我似乎无法使用注释来改变这种行为,所以看起来我将不得不使用另一种解决方案。

目前我正在采取以下丑陋的解决方案 - 编辑使得Nathan Hughes的回答明显减少了: - )

@Test
public void testDoThat() {
    try {
        new SomeService().doThat();
        Assert.fail();
    } catch(GenericException ex) {
        Assert.assertEquals(GenericException.class, ex.getClass());
    }
}

在JUnit框架中有更优雅的方式来实现我想要的东西吗?

3 个答案:

答案 0 :(得分:3)

您可以断言Exception的类是您所期望的:

@Test
public void testDoThat() {
    try {
        new SomeService().doThat();
        Assert.fail();
    } catch(GenericException ex) {
        assertEquals(GenericException.class, ex.getClass());
    }
}

同样摆脱了标志,如果没有抛出异常,则测试失败。

答案 1 :(得分:3)

BDD样式解决方案

JUnit 4 + Catch Exception + AssertJ

最优雅的解决方案;)可读,没有样板代码。

@Test
public void testDoThat() {

    when(new SomeService()).doThat();

    then(caughtException()).isExactlyInstanceOf(GenericException.class);

}

FEST Assertions 2 + Catch-Exceptions的代码相同。

源代码

依赖关系

org.assertj:assertj-core:1.4.0
com.googlecode.catch-exception:catch-exception:1.2.0

答案 2 :(得分:1)

您可以使用ExpectedException规则和自定义Hamcrest匹配器来指定可以抛出哪个类。

以下测试将打印您期望的RuntimeException实例,但是得到了IllegalArgumentException。

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

@Test
public void testThrows() {
    thrown.expect(isClass(RuntimeException.class));
    throw new IllegalArgumentException("FAKE");
}

public class ClassMatchMatcher extends BaseMatcher<Object> {
    private final Class<?> expectedClass;

    private ClassMatchMatcher(Class<?> expectedClass) {
        this.expectedClass = expectedClass;
    }

    @Override
    public boolean matches(Object item) {
        return expectedClass.equals(item.getClass());
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("an instance of ")
                .appendText(expectedClass.getName());
    }
}

public class ExtraMatchers {
   public static Matcher<Object> isClass(Class<?> aClass) {
      return new ClassMatchMatcher(aClass);
   }
}

编辑:添加了一个静态工厂方法,以使测试代码更清晰。