【问题标题】:How to assert that an exception is caught?如何断言异常被捕获?
【发布时间】:2014-09-10 08:56:05
【问题描述】:

我知道如何断言抛出异常。但是,我如何断言抛出了异常并成功捕获了它?例如,假设我有一个方法应该为无效输入抛出特定类型的异常

public static void myMethod(String value) {
    try {
        someExternalMethod(value);// can throw IllegalArgumentException
    } catch (IllegalArgumentException e) {
        System.out.println("Let me handle it differently");
    } catch (Exception e) {
        System.out.println("Not IllegalArgumentException");
    }
}

现在我想断言,对于某些值,该方法确实抛出了“IllegalArgumentException”,而不是其他一些异常。

【问题讨论】:

  • 对于相同的输入,先测试someExternalMethod 抛出异常,然后再测试myMethod 不抛出异常怎么样?
  • 你可以模拟方法抛出异常。
  • @tobias_k:虽然我为了简单起见写成someExternalMethod,但我调用实际方法的方式有点不同,我使用了一些深度重试策略,使用 Executors 来调用它。但我明白你的意思,如果我别无选择,我可能不得不改变我的测试方式
  • 这个问题可能是重复的。

标签: java junit exception-handling


【解决方案1】:

在测试myMethod 的上下文中,您不能(更重要的是,您不应该想要)检查someExternalMethod 是否抛出了IllegalArgumentException。事实上,您对myMethod 的测试不应假定已调用someExternalMethod:它是myMethod 的实现细节。

myMethod 捕获这些异常的真正原因是对其调用者隐藏它们。您应该通过传递导致它们的值来检查这些异常是否对您隐藏,并验证在这两种情况下都没有抛出任何东西。

测试someExternalMethod 及其引发的异常是通过测试someExternalMethod 而不是myMethod 完成的任务。

【讨论】:

    【解决方案2】:

    您错过了单元测试的重点 - 测试应该测试行为,而不是实现

    鉴于此假设,您应该测试myMethod 的行为是否符合IllegalArgumentException 发生时的预期。很难说除了给定参数的方法之外,单个String 是不可变的,没有返回值,也没有抛出异常。

    一个更好的例子可能是这种方法(这有点做作来证明这一点):

    public double divide(int numerator, int denominator)
    {
      try
      {
        return numerator / denominator;
      }
      catch (ArithmeticException e)
      {
        return Double.NaN;
      }
    }
    

    您的测试会断言除法是正确的,并且在发生错误时返回 NaN,如下所示:

    @Test
    public void testDivide()
    {
      assertEquals(2.0, divide(4, 2), 0);
    }
    
    @Test
    public void testDivideByZero()
    {
      assertTrue(Double.isNaN(divide(1, 0));
    }
    

    然后您可以像这样重写divide 方法:

    public double divide(int numerator, int denominator)
    {
      if (denominator == 0)
      {
        return Double.NaN;
      }
      else
      {
        return numerator / denominator;
      }
    }
    

    并且测试将确认我的系统的操作,因为divide 方法的行为保持不变。

    【讨论】:

    • 'Nan'不等于自己吗?
    • @C.R.实际上,在 IDE 中使用示例时,逻辑不太正确(我确实说过它有点做作来证明这一点),它应该是断言中使用的Double.isNaN
    【解决方案3】:

    catch 块按照它们的顺序进行评估。

    您的代码运行良好:如果是IllegalArgumentExceptionException 块将被忽略。

    【讨论】:

      【解决方案4】:
      1. 模拟方法someExternalMethod(value)强制抛出Exception
      2. 测试方法myMethod,检查没有抛出异常:

        @Test
        public void testMyMethod() {
           try {
              myMethod("value");
           } catch (Exception ex) {
              Assert.fail();
           }
        }
        

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-29
        • 2021-11-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-10
        相关资源
        最近更新 更多