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

发布于 2024-08-28 15:07:34 字数 1603 浏览 8 评论 0 原文

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

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

方法 A(JUnit 3 样式):创建一个扩展 TestCase 的类,并使用单词开始测试方法测试。当将类作为 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("所有测试");
    suite.addTestSuite(DummyTestA.class);
    suite.addTestSuite(DummyTestAbis.class);

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

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

I've found the proper use (or at least the documentation) of JUnit very confusing.
This question serves both as a future reference and as a real question.

If I've understood correctly, there are two main approaches to create and run a JUnit test:

Approach A (JUnit 3-style): create a class that extends TestCase, and start test methods with the word test. When running the class as a JUnit Test (in Eclipse), all methods starting with the word test are automatically run.

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);
    }
}

Approach B (JUnit 4-style): create a 'normal' class and prepend a @Test annotation to the method. Note that you do NOT have to start the method with the word 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);
    }
}

Mixing the two seems not to be a good idea, see e.g. this stackoverflow question:

Now, my questions(s):

  1. What is the preferred approach, or when would you use one instead of the other?
  2. Approach B allows for testing for exceptions by extending the @Test annotation like in @Test(expected = ArithmeticException.class). But how do you test for exceptions when using approach A?
  3. When using approach A, you can group a number of test classes in a test suite like this:

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

    But this can't be used with approach B (since each testclass should subclass TestCase). What is the proper way to group tests for approach B?

Edit: I've added the JUnit versions to both approaches

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

旧时模样 2024-09-04 15:07:34

区别相当简单:

  • 扩展 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 几乎相同。

The distinction is rather easy:

  • extending TestCase is the way unit tests were written in JUnit 3 (of course it's still supported in JUnit 4)
  • using the @Test annotation is the way introduced by JUnit 4

Generally you should choose the annotation path, unless compatibility with JUnit 3 (and/or a Java version earlier than Java 5) is needed. The new way has several advantages:

To test for expected exceptions in a JUnit 3 TestCase you'd have to make the text explicit.

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 introduced yet another API change, but still uses annotations. The new @Test annotation is org.junit.jupiter.api.Test (the "old" JUnit 4 one was org.junit.Test), but it works pretty much the same as the JUnit 4 one.

疯到世界奔溃 2024-09-04 15:07:34

我更喜欢 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 */
}

I have a preference for JUnit 4 (Annotation approach) because I find it more flexible.

If you want to build test suite in JUnit 4, you have to create a class grouping all tests like this:

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 */
}
·深蓝 2024-09-04 15:07:34

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

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

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

There is an unanswered part to your question, and that is "What is the proper way to group tests for approach B?"

The official answer is that you annotate a class with an @RunWith(Suite.class) and then use the @Suite.SuiteClasses annotation to list the classes. This is how the JUnit developers do it (listing every class in a suite manually). In many ways this approach is an improvement, in that it is trivial and intuitive to add before suite and after suite behaviors (just add an @BeforeClass and @AfterClass method to the the class annotated with the @RunWith - much better than the old TestFixture).

However, it does have a step backwards, in that annotations don't allow you to dynamically create the list of classes, and working around that problem gets a bit ugly. You have to subclass the Suite class and dynamically create the array of classes in the subclass and pass it to the Suite constructor, but this is an incomplete solution in that other subclasses of Suite (such as Categories) don't work with it and essentially do not support dynamic Test class collection.

温柔少女心 2024-09-04 15:07:34

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

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

这是来自 Spring 3.0 参考文档:

[警告] 旧版 JUnit 3.8 类
层次结构已弃用

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

You should use JUnit 4. It's better.

Much frameworks have started to deprecate the JUnit 3.8 support.

This is from the Spring 3.0 reference documentation:

[Warning] Legacy JUnit 3.8 class
hierarchy is deprecated

In general, you should always try to use the latest stable release of a framework when you start something new.

只等公子 2024-09-04 15:07:34
  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
    }
}
  1. The "preferred" approach would be to use annotations which have been introduced since Junit 4. They make a lot of things easier (see your second question)

  2. You can use a simple try/catch block for that:


public void testForException() {
    try {
        Integer.parseInt("just a string");
        fail("Exception should have been thrown");
    } catch (final Exception e) {
        // expected
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文