【问题标题】:Java test with expected = exception fails with assertion error [duplicate]具有预期 = 异常的 Java 测试因断言错误而失败 [重复]
【发布时间】:2016-08-10 16:06:40
【问题描述】:

我的测试用例有问题。

正在测试的方法有一个 try / catch 捕获 MalformedURLException 但在测试期间由于预期 MalformedURLException 的 Junit AssertionError 而失败。但我无法找出它实际上在抛出什么!这是我的代码(在 Eclipse 中创建为 MWE)。

我要测试的方法

public void throwMalFormedURLException(){

    String s = new String("www.google.com");

    try{
        url = new URL(s);
    }catch (Exception e){
        e.printStackTrace();
        e.getClass();
        e.getCause();
    }


}

测试方法

@Test (expected = MalformedURLException.class)
public void testThrowMalFormedURLException() {
    MWE testClass = new MWE();
    testClass.throwMalFormedURLException();
    System.out.println("End of test");
}

这是控制台的输出

测试结束错误详细信息是:java.net.MalformedURLException:无协议:www.google.com
在 java.net.URL.(URL.java:593)
在 java.net.URL.(URL.java:490)
在 java.net.URL.(URL.java:439)
在 MWE.throwMalFormedURLException(MWE.java:12)
在 testMWE.testThrowMalFormedURLException(testMWE.java:12)

在 Junit 控制台中它说:

java.lang.AssertionError:预期异常:Java.net.MalformedURLException

但 Junit 报告失败,即使控制台告诉我我遇到了 MalformedURLException。

我在这个测试中做错了什么?

感谢您的意见。

大卫

【问题讨论】:

    标签: java exception junit


    【解决方案1】:

    您正在捕获异常,因此它不会被抛出。

    如果您的意图是测试您是否正在捕获异常并将其正确地转发回“用户”,您应该专门为此创建测试。您可能不希望在单元测试中使用 UI 元素*,因此这是抽象和 DI 具有很大价值的地方。一种简单的方法是创建一个模拟对象,该对象将侦听错误消息并在收到消息时标记一个标志。如果设置了标志,您的单元测试会触发错误,然后通过。您还应该进行否定测试或断言在抛出异常之前未设置标志。

    *测试 UI 也是一个好主意,但它可能会有点慢。有多种工具可以实现自动化。它通常属于不同的测试阶段。您真的希望单元测试非常快,以便您可以非常频繁地运行它们。

    【讨论】:

    • 好吧,我觉得很傻,我如何测试这实际上发生了?因为我想确保这些类型的错误被捕获,所以我可以向我的用户发送适当的消息。
    • 很难给出确切的答案,因为我不知道应用程序的详细信息,但简而言之,我会创建一个测试,用于在出现异常时“向用户发送错误消息”被抓住了。为了更好地衡量,编写一个测试来验证没有抛出异常时没有发送此类消息。
    • 如果您将其作为一组点添加到您的回复中,我将接受您的解决方案。我必须承认这是我系统的最高端,但我很容易在应该创建的“消息窗口”中发现错误。谢谢
    • 我添加了更多细节。如果你不确定如何进行模拟,我可以稍后再举一个例子。
    • 感谢您提供额外信息。稍后我会考虑嘲笑,但现在我有足够的时间来解决我的问题。我将在另一个“向用户显示消息”类中捕获该方法,该类可以从我的 catch 中调用,并将所需的异常传递给它,以及消息(然后我可以测试这两者)。
    【解决方案2】:

    您编写的产品代码根本无法测试。更具体地说:这段代码首先没有任何“以编程方式”可观察到的副作用。

    含义:当你编写“生产代码”时,方法中的代码可以做三件可以观察到的事情:

    1. 对属于被测类字段的对象进行方法调用
    2. 返回一些值
    3. 抛出异常

    对于这些选项中的每一个,您都可以编写测试代码:

    1. 使用依赖注入,您可以将 mocked 对象放入您的测试类中。然后您可以检查是否在您的模拟对象上调用了预期的方法;使用您期望的参数。
    2. 您将调用该方法得到的结果与某个预期值进行比较
    3. 您使用expected 来确保引发特定异常

    当您查看代码时;你可以看到:它什么也没做。它仅对在方法内创建的对象进行操作。它不返回任何值。而且,最重要的是:它不会抛出异常!

    长话短说:捕获的异常并不是“离开”方法。它在那里被捕获,并且该方法正常结束。您打印有关捕获的异常的详细信息这一事实并没有改变这一点。

    所以,您要做的第一件事是:从生产代码中删除整个 try/catch!

    而且,如果您想进行更具体的测试,您可以执行以下操作:

    @Test
    public void testException() {
      try { 
        new MWE().throwMalFormedURLException();
        fail("should have thrown!");
      } catch ( MalFormedURLException me ) {
        assertThat(me.getMessage(), containsString("whatever"));
      }
    

    以上:

    1. 不抛出异常时失败
    2. 在抛出任何其他异常而不是 MalFormedURLException 时失败
    3. 允许您检查所引发异常的更多属性

    【讨论】:

    • 感谢您的回复,我给您一个+1,因为这是我在上面@Jimmy 的回复之后已经在我的代码中去的地方。感谢您的输入,因为按照您的示例,它使我的最终代码更清晰。
    【解决方案3】:

    这是一个有效的测试失败。测试断言调用throwMalFormedURLException() 会抛出MalformedURLException,但是由于你捕获了异常,它不会抛出它,所以测试失败。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-11
      • 1970-01-01
      • 1970-01-01
      • 2015-12-07
      • 1970-01-01
      • 2018-06-29
      相关资源
      最近更新 更多