Java - TestNG:为什么我的断言在 try-catch 块中写入时总是通过

Java - TestNG : Why does my Assertion always passes when written within try-catch block

我正在尝试使用 org.testng.Assert 的简单代码来断言 2 个用例。在第一个用例中,我断言 2 个不相等的值 Fail 正确。

但是在第二个用例中,当我在 try-catch 块中断言 2 个不相等的值时,结果总是返回为 Pass

我的代码如下:

package demo;
import org.testng.Assert;
import org.testng.annotations.Test;
public class Q43710035 
{

    @Test
    public void test1() 
    {
        System.out.println("Within test1");
        int a = 12;
        int b =20;
        Assert.assertEquals(a, b);

    }

    @Test
    public void test2() 
    {
        System.out.println("Within test2");
        int a = 12;
        int b =20;

        try 
        {
            Assert.assertEquals(a, b);
        }catch(Throwable t)
        {
            System.out.println("Exception Occurred");
        }
    }
}

我得到的结果是:

Within test1
Within test2
Exception Occurred
PASSED: test2
FAILED: test1
java.lang.AssertionError: expected [20] but found [12]
at org.testng.Assert.fail(Assert.java:94)

我的问题是:

  1. 在 test2() 中,虽然断言失败了,但为什么不执行此 Test
  2. 在 test2() 中,似乎 try 块失败了,因此执行到达 catch 块并打印 Exception Occurred。为什么在执行断言代码时 try 块会在这里失败?

如果您查看 assertEquals 方法的源代码,您会发现它全部归结为 fail 方法(许多其他断言也是如此)。

public static void fail(String message) {
    if(message == null) {
        throw new AssertionError();
    } else {
        throw new AssertionError(message);
    }
}

如我们所见,它抛出 AssertionError,您在 catch(Throwable t) 中捕获了它。所以 JUnit 没有办法告诉测试失败,从而宣布测试通过。

如果捕获异常是您测试的一部分(您期待异常),我建议您查看 JUnit 文档:Exception testing

如果你翻过junit4的源码,https://github.com/junit-team/junit4/blob/master/src/main/java/junit/framework/Assert.java#L71

您将了解 test1 失败的原因

第 1 部分:

/**
 * Asserts that two objects are equal. If they are not
 * an AssertionFailedError is thrown with the given message.
 */
static public void assertEquals(String message, Object expected, Object actual) {
    if (expected == null && actual == null) {
        return;
    }
    if (expected != null && expected.equals(actual)) {
        return;
    }
    failNotEquals(message, expected, actual); //It calls Part#2
}

第 2 部分:

static public void failNotEquals(String message, Object expected, Object actual) {
    fail(format(message, expected, actual)); //It calls Part#3 format(...) method
}

第 3 部分:

public static String format(String message, Object expected, Object actual) {
    String formatted = "";
    if (message != null && message.length() > 0) {
        formatted = message + " ";
    }
    return formatted + "expected:<" + expected + "> but was:<" + actual + ">";
}

所以你已经收到第 3 部分的 return 消息

java.lang.AssertionError: expected [20] but found [12]

要全面了解 Exceptions JUnit 规则,请阅读 following tutorial:

预期异常 JUnit 规则

要断言 JUnit 抛出了异常,通常使用 try/fail/catch 惯用语或 @Test 注释的预期元素。尽管比前者更简洁,但有人认为使用 expected 并不支持您可能想要测试的所有情况。该示例是在异常之后执行附加测试或针对实际异常消息进行测试。

JUnit 4.7 引入了下一个进展,一个提供两全其美的@Rule。本文权衡了每种方法的优缺点,并仔细研究了每种方法的语法。 try/fail/catch 成语

典型的模式是捕获异常或者如果从未抛出异常则显式失败。

@Test
public void example1() {
    try {
        find("something");
        fail();
    } catch (NotFoundException e) {
        assertThat(e.getMessage(), containsString("could not find something"));
    }
    // ... could have more assertions here
}

这将以下列方式突出显示失败。

java.lang.AssertionError: expected an exception
    at org.junit.Assert.fail(Assert.java:91)
    at bad.roboot.example.ExceptionTest.example1(ExceptionTest.java:20)
    ...

该惯用语具有潜在的优势,因为它提供了针对实际异常进行断言以及在预期之后执行额外工作的机会。然而,除了噪音之外,主要缺点是很容易忘记包含失败调用。如果真正先做测试,我们总是 运行 测试红色,这不会是一个问题,但事情往往会漏网。在实践中,我见过太多因缺失而导致误报的示例。

@测试(预期=Exception.class)

使用预期的元素,我们可以重写测试如下。

@Test (expected = NotFoundException.class)
public void example2() throws NotFoundException {
    find("something");
    // ... this line will never be reached when the test is passing
}

这将导致以下失败。

java.lang.AssertionError: Expected exception: bad.robot.example.NotFoundException

资源 Link: What exactly does assertEquals check for when asserting lists?

你的第二个案例充满了问题,这就是它表现如此奇怪的原因。查看用数字标记的行:

    try 
    {
        Assert.assertEquals(a, b); // 1
    }catch(Throwable t) // 2
    {
        System.out.println("Exception Occurred"); // 3
    }

1 - 'assert*' 方法调用不应由 try-catch 块包装。它们旨在检查数据并通过抛出错误 (!) 来处理数据的无效性。

2 - 你正试图捕捉所有可以在 try 部分抛出的东西。通常情况下应用程序的业务逻辑使用异常,而不是错误。异常表明出现了一些问题,您可以从中恢复。错误主要表明出现了一些严重的问题,如(硬盘故障等),您只需要在应用程序停止之前处理应用程序的数据。 Exception 和 Error 继承自 Throwable。 'assert*' 方法以这种方式设计以抛出错误,特别是不会被 'catch' 块捕获。

3 - 如果不处理捕获的异常,您只是忽略了它。这就是为什么您的方法总是会成功完成的原因。

要更正第二个测试,您可以: a) 从方法体中删除 try-catch 部分 b) 将 't' 参数的类型从 Throwable 更改为 Exception c) 在 'catch' 块

的末尾添加 'throw t'

我也遇到过类似的问题,后来在理解Java的时候,调用方法想知道被调用方法中的异常时,被调用方法应该包含'throw exception;'语句在它的 Catch 块中。

这样,

@Test
public void test2() 
{
    System.out.println("Within test2");
    int a = 12;
    int b =20;

    try 
    {
        Assert.assertEquals(a, b);
    }catch(Exception e)
    {
        System.out.println("Exception Occurred");
        throw e;
    }
}

TestNG 会知道,抛出异常。然后,TestNG 将使该方法失败。
请注意,e.printStackTrace();也不会使您的测试用例失败。