【问题标题】:Try Catch block works but test assertThrows fail (Junit 5)尝试 Catch 块有效,但测试 assertThrows 失败(Junit 5)
【发布时间】:2019-03-07 07:41:42
【问题描述】:

我正在尝试学习本教程JUnit 5: How to assert an exception is thrown?

我使用 Java 10、IntelliJ 2018 和 Junit 5。

我制作了一个计算器应用程序,可以将 2 个分数相加。它检查输入的分母是否为 0。

当我运行测试时,打印出异常消息“未定义的数学表达式”,但我的 IDE 显示“预期 java.lang.Throwable 被抛出,但没有抛出任何东西。”我认为我的代码范围有问题?我是新手,请多指教。我提供了以下代码和测试:

public class Calculator {
    public static int[] calculate (int firstNumerator, int firstDenominator, int secondNumerator, int secondDenominator) {

        String exceptionMessage = "Undefined Math Expression";
        int resultNumerator;
        int resultDenominator;
        int[] result = new int[2];

        resultNumerator =  (firstNumerator * secondDenominator) +
                (secondNumerator * firstDenominator);
        resultDenominator = firstDenominator * secondDenominator;

        try {
            if (resultDenominator == 0) {
                  throw (new Throwable(exceptionMessage));
            } else {
                result[0] = resultNumerator;
                result[1] = resultDenominator;
            }
        } catch (Throwable e) {
           System.out.println(e.getMessage());
        }

        return result;
    }
}

测试:

class CalculatorTest {
    @Test
    void denominatorContainsZero() {
        assertThrows(Throwable.class, () -> {
            Calculator.calculate(0,0,0,0);
        });
    }
}

【问题讨论】:

  • 你应该很少看到Throwable;你应该(有效地)永远抛出Throwable。在这种情况下,例外是完全没有必要的:只需打印消息。

标签: java junit5


【解决方案1】:

Throwabletry catch 块捕获,因此 Junit 无法访问它。尝试删除 try catch 块。

【讨论】:

  • 我试图删除:catch (Throwable e) { System.out.println(e.getMessage()); } 但系统说未处理的异常。系统强迫我处理它。如何让我的函数在不处理的情况下抛出异常?
  • 解决方法可能是将方法签名更改为public static int[] calculate (int firstNumerator, int firstDenominator, int secondNumerator, int secondDenominator) throws Throwable
  • @user3270418 但是,我不建议使用Throwable。您可能想使用IllegalArgumentException
  • 我试图在我的方法签名中添加“throws Throwable”,但它仍然希望我抓住它 o_O。它说“错误:(15, 63) java: 未报告的异常 java.lang.Throwable; 必须被捕获或声明被抛出”
【解决方案2】:

您实际上并没有抛出异常,而是正在捕获它。为此,您应该删除 try catch 块。

【讨论】:

    【解决方案3】:

    这里的误解似乎在于 JUnit 可以实际看到的内容。

    JUnit 并不神奇:它只是普通的旧 Java。它看不到您的方法内部以查看它们在做什么。它所能看到的只是其他代码在执行方法时所能看到的:返回值和未捕获的异常(以及方法的任何副作用,如果它们对调用代码可见)。

    从调用者的角度来看,这里的方法不会引发异常:在内部,它会引发异常,但会捕获并处理它。

    如果您希望 JUnit 测试是否引发了异常,则无需捕获该异常。

    抛出异常然后自己捕获并处理它永远不是 (*) 正确的做法。重点是什么?你可以简单地做你做的事情来处理它,而不抛出异常。由于需要捕获整个堆栈跟踪,因此抛出异常的成本很高。

    Throwable 绝不是 (*) 要抛出的正确异常。这是返回Object 的异常“等效”:它没有向调用者传达有关异常的类型信息,然后调用者要么必须做很多工作来尝试处理它;或者,更现实地说,应该自己传播它。 IllegalArgumentException 是在此处抛出的正确异常,如果您确实需要抛出(而不是捕获)异常。

    Throwable 很少是正确的。 ThrowableExceptionError 的超类型,因此您可能会无意中捕获Error,例如OutOfMemoryError,它不应该被捕获,因为除了使您的程序崩溃之外没有任何合理的事情可以做。抓住最具体的类型;这也意味着您应该尽可能抛出最具体的类型(或者,至少是适合抽象的类型)。


    (*) 这是“从不”,如“好的,在有限的情况下它可能是合适的”。但除非你明白这些是什么,否则不要这样做。

    【讨论】:

    • 我试图做到这一点,先生,但它迫使我抓住它,即使我在我的方法签名中添加了“throws Throwable”。它仍然要我抓住。
    • @user3270418 那是因为你抛出了一个检查异常。如果你抛出一个未经检查的异常,比如IllegalArgumentException,你不需要声明throws
    • @Andy Turner 好的,先生,您的意思是删除 try 和 catch,然后将 Throwable 更改为 IllegalArgumentException。它现在抛出异常。但需要同时删除 try 和 catch。所以总而言之,如果有尝试,就需要有一个捕获,对吗?
    • @user3270418 去掉try,去掉catch,还有throw new IllegalArgumentException(whateverMessage);
    猜你喜欢
    • 2015-10-04
    • 1970-01-01
    • 1970-01-01
    • 2021-02-16
    • 1970-01-01
    • 1970-01-01
    • 2018-01-04
    • 1970-01-01
    • 2015-05-22
    相关资源
    最近更新 更多