【问题标题】:JUnit 4 : Expect one exception multiple timesJUnit 4:多次预期一个异常
【发布时间】:2018-01-03 11:21:28
【问题描述】:

我有以下代码:

@Test(expected = IllegalArgumentException.class)
public void failureTest()    {
    testedObject.supposedToFail("");
    testedObject.supposedToFail(null);
}

运行此程序时,我无法保证会抛出带有null 参数的IllegalArgumentException。事实上,每当 JUnit 遇到第一个异常时,它就会停止整个方法的运行。

考虑到我必须为这个类尝试的测试用例数量(约 20 个),我怀疑编写 20 个方法,每个方法都期望一个特定的异常(虽然它们通常是相同的)是有效的。

有什么方法可以尝试一次抛出特定异常的每个方法? (例如,对于我的示例,您将通过这两种方法)

谢谢

【问题讨论】:

  • "运行此程序时,我无法保证我会抛出带有null 参数的IllegalArgumentException。" 为什么不呢?在单元测试中,测试代码应该根据输入和设置以完全相同的方式运行。
  • @Timothy 因为 @Expected 注释以这种方式工作。当它捕获第一个IllegalException 时,它认为整个测试方法已完成并跳过其他所有内容。
  • @YassineBadache 您的生产代码如何在一次调用中抛出多个异常*?
  • 我认为你没有得到这个测试的目标。如果您的 String 参数为 null 或为空,请使用引发异常的代码。您可以测试您的参数是否为空或为空。这使得有两个案例可以尝试。如果您的类包含 10 个预期这种行为的方法,我应该编写 20 个单元测试吗?这里的目标是在单个测试方法中尝试所有抛出此异常的方法。下面的答案似乎令人满意,我会试一试。

标签: java exception junit expected-exception


【解决方案1】:

不幸的是,辅助方法在这种情况下不起作用,因为即使只有一个辅助方法调用抛出异常,@Test 方法也会通过。

我没有找到一个很好的方法来实现这样的测试并最终得到这样的结果:

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

@Test
public void testThrowIllegalArgumentExceptionForEmptyParam() {
    assertExceptionForParam("", IllegalArgumentException.class);
}

@Test
public void testThrowNullPointerExceptionForNullParam() {
    assertExceptionForParam(null, NullPointerException.class);
}

private void assertExceptionForParam(String param, Class expectedExceptionClass) {
    thrown.expect(expectedExceptionClass);
    testedObject.supposedToFail(param);
}

如果测试失败,您将清楚地了解失败的地点和时间,而且您的代码不会包含很多样板。

【讨论】:

    【解决方案2】:

    我会使用辅助方法并这样做:

    编辑:这不起作用,请参阅替代工作解决方案

    @Rule
    public ExpectedException thrown = ExpectedException.none();
    
    @Test
    public void myTest() {
        List<Object[]> paramsList = Arrays.asList(
            new Object[] {"", IllegalArgumentException.class},
            new Object[] {null, NullPointerException.class});
        paramsList.forEach(a -> assertExceptionForParam((String)a[0], (Class)a[1]));
    }
    
    private void assertExceptionForParam(String param, Class expectedExceptionClass) {
        thrown.expect(expectedExceptionClass);
        testedObject.supposedToFail(param);
    }
    

    替代工作解决方案,在 MIRZAK 发表评论后进行更改

    我的解决方案实际上似乎只测试列表中的第一个案例。这是一个可以测试它们的工作版本

    @Test
    public void myTest() {
        List<Object[]> paramsList = Arrays.asList(
            new Object[] {null, NullPointerException.class},
            new Object[] {"", IllegalArgumentException.class},
            new Object[] {"zip", NullPointerException.class});
        paramsList.forEach(a -> assertExceptionForParam((String)a[0], (Class)a[1]));
    }
    
    private void assertExceptionForParam(String param, Class expectedExceptionClass) {
        boolean pass = false;
        try {
            testedObject.supposedToFail(param);
        } catch(Exception e) {
            pass = e.getClass() == expectedExceptionClass;
        }
        Assert.assertTrue("test failed for param:" + param + " and Exception "+expectedExceptionClass, pass);
    }
    

    按预期输出:

    java.lang.AssertionError: test failed for param:zip and Exception class java.lang.NullPointerException
    

    【讨论】:

    • 如果您将一个值添加到不应引发异常的列表(在末尾),此测试仍将通过。有没有办法“重置”抛出的对象?
    • @mirzak 恐怕你是对的。我用我测试过的有效解决方案更改了帖子
    【解决方案3】:

    注意,这不是 junit 的解决方案,但让我分享如何在 spock 上实现相同的测试:

    def "supposedToFail(String) throws IllegalArgumentException when the given argument is null or blank"() {
        when:
        testedObject.supposedToFail(givenArgument)
    
        then:
        thrown(IllegalArgumentException)
    
        where:
        givenArgument << [null, '', '       ', '\n']
    }
    

    Spock可以和junit一起用在你的Java项目上没有任何问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-27
      • 1970-01-01
      • 2011-07-29
      • 2011-05-28
      相关资源
      最近更新 更多