JUnit困惑:使用“扩展TestCase”还是“ @Test”?


152

我发现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);
    }
}

混合两者似乎不是一个好主意,请参见例如这个stackoverflow问题

现在,我的问题是:

  1. 首选的方法是什么,或者何时使用一种方法代替另一种方法?
  2. 方法B允许通过扩展@Test注释(如中的)来测试异常@Test(expected = ArithmeticException.class)但是,使用方法A时如何测试异常?
  3. 使用方法A时,可以在测试套件中将多个测试类分组,如下所示:

    TestSuite suite = new TestSuite("All tests");
    suite.addTestSuite(DummyTestA.class);
    suite.addTestSuite(DummyTestAbis.class);

    但这不能与方法B一起使用(因为每个测试类都应该将TestCase子类化)。对方法B进行分组测试的正确方法是什么?

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


我看过了extends TestCase,然后每个测试也都带有注解,@Test以使事情变得混乱。:)
EM-Creations

Answers:


119

区别很简单:

  • 扩展TestCase是在JUnit 3中编写单元测试的方式(当然,在JUnit 4中仍支持它)
  • 使用@Test注释是JUnit 4引入的方法

通常,您应该选择注释路径,除非需要与JUnit 3(和/或Java 5之前的Java版本)兼容。新方法具有以下优点:

要在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

3
@thSoft:并不经常使用它,但是例如,我偶尔要确保异常方法提到有问题的字段。那么简单assertTrue(e.getMessage().contains("foo"))可能会有用。
Joachim Sauer'4

1
即使在JUnit4中,当您必须检查消息或异常的其他某些属性(例如原因)时,这也是一个重要的习惯用法。该expected方法仅检查类型。
Yishai'4

@Yishai:是的,但是大多数时候,如果该方法在有问题的输入上抛出正确的Exception类型,我就已经很满意。
Joachim Sauer'4

因此,JUnit 5在异常测试中进行了重大更改。assertThrows()非常棒:-)
Marcus K.

25

我偏爱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 */
}

15

您的问题有一个未解决的部分,那就是“对方法B进行分组测试的正确方法是什么?”

官方的答案是,您用@RunWith(Suite.class)注释一个类,然后使用@ Suite.SuiteClasses注释列出这些类。JUnit开发人员就是这样做的(手动列出套件中的每个类)。从许多方面来说,这种方法都是一种改进,因为在套件之前和套件之后的行为中添加是简单而直观的(只需将@BeforeClass和@AfterClass方法添加到以@RunWith注释的类中,比旧的TestFixture更好) )。

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


1
为此+1。在完成编写动态解决方案以将Tests添加到TestSuite的任务之后,我不得不在每个Tests中扩展TestCase。反过来,这又破坏了以前的工作单元测试,该单元测试使用JUnit4批注定义了预期的异常。我换一种方式来动态填充测试套件搜索已经使我这个线程,特别是你的答案,我相信这是为数不多的剩余理想的原因继续使用JUnit 3.一个
8bitjunkie

4

您应该使用JUnit4。更好。

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

这来自Spring 3.0参考文档:

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

通常,启动新内容时,应始终尝试使用最新稳定的框架版本。


1
  1. “首选”方法是使用从Junit 4开始引入的注释。它们使很多事情变得容易(请参阅第二个问题)

  2. 您可以为此使用一个简单的try / catch块:


public void testForException() {
    try {
        Integer.parseInt("just a string");
        fail("Exception should have been thrown");
    } catch (final Exception e) {
        // expected
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.