ChatGPT解决这个技术问题 Extra ChatGPT

JUnit 混淆:使用“扩展 TestCase”或“@Test”?

我发现 JUnit 的正确使用(或至少是文档)非常令人困惑。这个问题既可以作为未来的参考,也可以作为一个真实的问题。

如果我理解正确的话,创建和运行 JUnit 测试有两种主要方法:

方法 A(JUnit 3 风格):创建一个扩展 TestCase 的类,并以单词 test 开始测试方法。在将类作为 JUnit 测试(在 Eclipse 中)运行时,所有以单词 test 开头的方法都会自动运行。

import junit.framework.TestCase;

public class DummyTestA extends TestCase {

    public void testSum() {
        int a = 5;
        int b = 10;
        int result = a + b;
        assertEquals(15, result);
    }
}

方法 B(JUnit 4 风格):创建一个“普通”类并在方法前添加 @Test 注释。请注意,您不必以单词 test 开始该方法。

import org.junit.*;
import static org.junit.Assert.*;

public class DummyTestB {

    @Test
    public void Sum() {
        int a = 5;
        int b = 10;
        int result = a + b;
        assertEquals(15, result);
    }
}

将两者混合似乎不是一个好主意,请参见例如 this stackoverflow question

现在,我的问题:

首选方法是什么,或者您什么时候使用其中一种而不是另一种?方法 B 允许通过扩展 @Test 注释来测试异常,如 @Test(expected = ArithmeticException.class)。但是在使用方法 A 时如何测试异常?使用方法 A 时,您可以将多个测试类分组到一个测试套件中,如下所示: TestSuite suite = new TestSuite("All tests"); suite.addTestSuite(DummyTestA.class); suite.addTestSuite(DummyTestAbis.class);但这不能与方法 B 一起使用(因为每个测试类都应该是 TestCase 的子类)。对方法 B 进行分组测试的正确方法是什么?

编辑:我已将 JUnit 版本添加到这两种方法中

我见过 extends TestCase,然后每个测试也用 @Test 注释只是为了混淆。 :)

M
Marcono1234

区别很简单:

扩展 TestCase 是用 JUnit 3 编写单元测试的方式(当然 JUnit 4 仍然支持它)

使用@Test注解是JUnit 4引入的方式

通常您应该选择注释路径,除非需要与 JUnit 3(和/或早于 Java 5 的 Java 版本)兼容。新方式有几个优点:

@Test 注释更明确,更容易在工具中支持(例如,通过这种方式搜索所有测试很容易)

可以使用 @Before/@BeforeClass 和 @After/@AfterClass 注释多个方法,从而提供更大的灵活性

支持诸如 ExpectedException 之类的 @Rule 注释

支持@Ignored 注解

使用 @RunWith 支持替代测试运行器

要测试 JUnit 3 TestCase 中的预期异常,您必须明确文本。

public void testMyException() {
  try {
    objectUnderTest.myMethod(EVIL_ARGUMENT);
    fail("myMethod did not throw an Exception!");
  } catch (MyException e) {
    // ok!
    // check for properties of exception here, if desired
  }
}

JUnit 5 引入了另一项 API 更改,但仍使用注释。新的 @Test 注释是 org.junit.jupiter.api.Test(“旧”JUnit 4 注释是 org.junit.Test),但它与 JUnit 4 注释几乎相同。


有用且彻底的答案,但我不完全理解“检查异常消息”。检查硬编码字符串将成为维护的噩梦。您的意思一定是“检查您的特定异常类型的属性”。
@thSoft:它不经常使用,但偶尔我想确保异常方法提到了违规字段。那么一个简单的 assertTrue(e.getMessage().contains("foo")) 可能会很有用。
即使在 JUnit4 中,当您必须检查异常的消息或其他一些属性(例如原因)时,这也是一个重要的习惯用法。 expected 方法仅检查类型。
@Yishai:是的,但大多数时候,如果该方法在有问题的输入上抛出正确类型的异常,我已经很满足了。
出于这个原因,JUnit 5 在异常测试方面做出了重大改变。 assertThrows() 太棒了:-)
G
Grimmy

我偏爱 JUnit 4(注释方法),因为我发现它更灵活。

如果您想在 JUnit 4 中构建测试套件,您必须创建一个将所有测试分组的类,如下所示:

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;


@RunWith(Suite.class)
@SuiteClasses({
    Test1.class,
    Test2.class,
    Test3.class,
    Test4.class
})public class TestSuite
{
 /* empty class */
}

Y
Yishai

您的问题有一个未回答的部分,那就是“为方法 B 分组测试的正确方法是什么?”

官方的回答是你用@RunWith(Suite.class) 注释一个类,然后使用@Suite.SuiteClasses 注释列出这些类。这就是 JUnit 开发人员的做法(手动列出套件中的每个类)。在许多方面,这种方法是一种改进,因为在套件之前和之后添加行为是微不足道和直观的(只需将 @BeforeClass 和 @AfterClass 方法添加到使用 @RunWith 注释的类 - 比旧的 TestFixture )。

但是,它确实倒退了一步,因为注释不允许您动态创建类列表,并且解决该问题有点难看。您必须对 Suite 类进行子类化并在子类中动态创建类数组并将其传递给 Suite 构造函数,但这是一个不完整的解决方案,因为 Suite 的其他子类(例如 Categories)不能使用它,而且本质上不支持动态测试类集合。


为此+1。在着手编写将测试添加到 TestSuite 的动态解决方案之后,我不得不在我的每个测试中扩展 TestCase。这反过来又破坏了以前使用 JUnit4 注释来定义预期异常的工作单元测试。我寻找一种动态填充测试套件的方法使我找到了这个线程,特别是你的答案,我相信这是继续使用 JUnit 3 的少数几个理想的理由之一。
h
husayt

您应该使用 JUnit 4。它更好。

许多框架已经开始弃用 JUnit 3.8 支持。

这是来自 Spring 3.0 参考文档:

[警告] 不推荐使用旧版 JUnit 3.8 类层次结构

通常,当您开始新事物时,您应该始终尝试使用框架的最新稳定版本。


b
black666

“首选”方法是使用自 Junit 4 以来引入的注释。它们使很多事情变得更容易(请参阅您的第二个问题)您可以为此使用简单的 try/catch 块:


public void testForException() {
    try {
        Integer.parseInt("just a string");
        fail("Exception should have been thrown");
    } catch (final Exception e) {
        // expected
    }
}