setUp/tearDown(@ Before/@ After)为什么我们在JUnit中需要它们?

mhs*_*ams 62 java junit junit4 junit3

我相信我们都知道setUp(@Before)将在任何测试方法之前执行,而tearDown(@After)将在测试方法之后执行.

我们也知道Junit将为每个测试方法创建一个Test实例.

我的问题是,我们可以将setUp方法内容移动到类Constructor并删除setUp方法吗?是否有任何特定的理由保持setUp方法?

Pas*_*ent 59

这篇(旧的)JUnit最佳实践文章如下:

不要使用测试用例构造函数来设置测试用例

在构造函数中设置测试用例不是一个好主意.考虑:

public class SomeTest extends TestCase
   public SomeTest (String testName) {
      super (testName);
      // Perform test set-up
   }
}
Run Code Online (Sandbox Code Playgroud)

想象一下,在执行设置时,设置代码会抛出一个 IllegalStateException.作为响应,JUnit会抛出一个 AssertionFailedError,表明测试用例无法实例化.以下是生成的堆栈跟踪示例:

junit.framework.AssertionFailedError: Cannot instantiate test case: test1   
    at junit.framework.Assert.fail(Assert.java:143)
    at junit.framework.TestSuite.runTest(TestSuite.java:178)
    at junit.framework.TestCase.runBare(TestCase.java:129)
    at junit.framework.TestResult.protect(TestResult.java:100)
    at junit.framework.TestResult.runProtected(TestResult.java:117)
    at junit.framework.TestResult.run(TestResult.java:103)
    at junit.framework.TestCase.run(TestCase.java:120)
    at junit.framework.TestSuite.run(TestSuite.java, Compiled Code)
    at junit.ui.TestRunner2.run(TestRunner.java:429)
Run Code Online (Sandbox Code Playgroud)

这种堆栈跟踪证明相当无意义; 它只表示测试用例无法实例化.它没有详细说明原始错误的位置或原产地.缺乏信息使得很难推断出异常的根本原因.

不是在构造函数中设置数据,而是通过覆盖执行测试设置setUp().setUp()正确报告任何抛出的异常.将此堆栈跟踪与前一个示例进行比较:

java.lang.IllegalStateException: Oops
    at bp.DTC.setUp(DTC.java:34) 
    at junit.framework.TestCase.runBare(TestCase.java:127)
    at junit.framework.TestResult.protect(TestResult.java:100)
    at junit.framework.TestResult.runProtected(TestResult.java:117)
    at junit.framework.TestResult.run(TestResult.java:103)
    ...
Run Code Online (Sandbox Code Playgroud)

这个堆栈跟踪信息更丰富; 它显示了抛出(IllegalStateException)和从哪里抛出的异常.这使得解释测试设置失败变得容易得多.


Bjo*_*rnS 24

在工作中,我们发现了一些相当有趣的东西来回答你的问题.当你运行一个测试套件,特别是一个大的测试集(200+)的JUnit开始使用的内存很多,这是因为在运行任何实际的测试方法之前所有的测试都实例化.

我们碰到了一个"内存泄漏",因为这一点,因为我们使用Spring来为我们的数据库测试一些JPA EntiryManager对象线,这成为对象的很多,通过我们得到OutOfMemory异常测试了大量的内存和大约一半.

恕我直言,最好的做法是使用安装和拆卸注入你的依赖和空出的任何和所有类引用,这将使你的测试运行速度更快,为您节省了很多头疼的!

希望你从我们的错误中吸取教训:)


Ber*_*t F 23

这有三个很好的理由.综上所述:

  1. 某些情况可能更倾向于在测试用例执行之前尽可能延迟设置测试装置.

  2. 某些测试用例可能是深度测试用例继承层次结构的一部分.可能最好推迟设置测试夹具,直到构造函数的完整层次结构完成为止.

  3. 如果设置代码在setUp()中失败而不是在构造函数中失败,则可以获得更好的诊断.

1.推迟设置夹具直到测试用例之前

可用性设计
http://www.artima.com/weblogs/viewpost.jsp?thread=70189

......正如Elliotte Rusty Harold所说的那样,如果你要为每个测试方法创建一个新的TestCase实例,"为什么他们会厌烦setUp()方法?" 您可以使用TestCase构造函数.

我听说Bruce Eckel指出在setUp()中创建fixture与在TestCase构造函数中创建它之间存在一个微妙的区别.JUnit预先创建所有TestCase实例,然后为每个实例调用setup(),test方法和tearDown().换句话说,细微的区别在于构造函数都是预先批量调用的,而setUp()方法是在每个测试方法之前调用的.但这在实践中似乎并没有那么有用.

2.在实例化所有测试用例之后,推迟设置夹具

教程的Java极限编程 - 4.6设置和删除
http://etutorials.org/Programming/Java+extreme+programming/Chapter+4.+JUnit/4.6+Set+Up+and+Tear+Down/

您可能想知道为什么要编写setUp()方法而不是简单地初始化测试用例的构造函数中的字段.毕竟,由于为每个测试方法创建了一个新的测试用例实例,因此总是在setUp()之前调用构造函数.在绝大多数情况下,您可以使用构造函数而不是setUp()而不会产生任何副作用.

如果您的测试用例是更深层继承层次结构的一部分,您可能希望推迟对象初始化,直到完全构造派生[test]类的实例.这是一个很好的技术原因,您可能希望使用setUp()而不是构造函数进行初始化.使用setUp()和tearDown()也很适合文档,只是因为它可以使代码更容易阅读.

3.安装失败时更好的诊断

JUnit最佳实践(JavaWorld)
http://www.javaworld.com/jw-12-2000/jw-1221-junit.html

在构造函数中设置测试用例不是一个好主意....

想象一下[在测试用例构造函数中完成设置的代码],在执行设置时,安装代码会抛出IllegalStateException.作为响应,JUnit将抛出AssertionFailedError,指示无法实例化测试用例....

这个堆栈跟踪[测试用例构造函数中的设置代码中抛出的异常]证明相当无法提供信息; 它只表示测试用例无法实例化.

不是在构造函数中设置数据,而是通过重写setUp()来执行测试设置.正确报告setUp()中抛出的任何异常....

这个堆栈跟踪[在setUp()方法而不是测试用例构造函数中抛出的异常]提供了更多信息; 它显示抛出了哪个异常(IllegalStateException)以及从哪里开始.这使得解释测试设置失败变得容易得多.


Ric*_*chN 6

自定义SpringJUnit4ClassRunner运行器,例如可能需要在构造函数和@Before方法之间运行一些代码.在这种情况下,跑步者可以注入一些@Before方法所需的依赖性.但依赖注入只能在构造对象后运行.