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

我相信大家都知道setUp(@Before)会在任何testing方法执行之前执行,而tearDown(@After)会在执行testing方法之后执行。

我们也知道Junit会创build一个Test 每个testing方法的实例。

我的问题是,我们可以将setUp方法内容移动到类Constructor并删除setUp方法吗? 有没有什么特定的原因保持setUp方法?

这(旧的) JUnit最佳实践文章就是这样的:

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

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

public class SomeTest extends TestCase public SomeTest (String testName) { super (testName); // Perform test set-up } } 

想象一下,执行安装程序时,安装程​​序代码会抛出IllegalStateExceptionexception。 作为回应,JUnit会抛出一个AssertionFailedError ,表明testing用例不能被实例化。 以下是生成的堆栈跟踪的示例:

 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) 

这个堆栈跟踪certificate是非信息的; 它只是表示testing用例不能被实例化。 它没有详细说明原始错误的位置或原产地。 信息的缺乏使得很难推断出例外的根本原因。

不用在构造函数中设置数据,而是通过覆盖setUp()执行testing设置。 setUp()引发的任何exception都会正确报告。 比较这个堆栈跟踪与前面的例子:

 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) ... 

这个堆栈跟踪是更多的信息; 它显示抛出了哪个exception( IllegalStateException )和从哪里。 这使得解释testing设置的失败变得容易得多。

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

我们遇到了“内存泄漏”,因为我们使用Spring为我们的数据库testing连接了一些JPA EntiryManager对象,这变成了很多对象和大量的内存,大概在通过testing的一半之后,我们得到了OutOfMemoryexception。

恕我直言,最好的做法是使用setUp和tearDown注入您的依赖关系,并将任何和所有类的引用归零,这将使您的testing运行得更快,并为您节省很多头疼!

希望你从我们的错误中学习:)

这里有三个很好的原因。 综上所述:

  1. 在某些情况下,可能希望尽可能延迟设置testing夹具,直到执行testing用例。

  2. 一些testing用例可能是深度testing用例inheritance层次结构的一部分。 推迟设置testing夹具,直到构造函数完整的层次结构完成为止。

  3. 如果安装程序代码在setUp()中失败,而不是在构造函数中失败,则会得到更好的诊断结果。

推迟在testing用例之前设置灯具

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

正如Elliotte Rusty Harold所说的那样,如果你要为每个testing方法创build一个新的TestCase实例, “为什么地狱会使用setUp()方法? 您可以使用TestCase构造函数。

我听说Bruce Eckel指出,在setUp()中创build你的fixture与在TestCase构造器中创build它之间有一个微妙的区别 。 JUnit先创build所有的TestCase实例然后为每个实例调用setup(),test方法和tearDown() 。 换句话说, 细微的区别在于构造函数都是先调用的,而setUp()方法是在每个testing方法之前调用的 。 但是这在实践中似乎没有什么用处。

2.推迟设置灯具,直到所有的testing用例被实例化

ETutorial的Java极限编程 – 4.6设置和撕下
http://etutorials.org/Programming/Java+extreme+programming/Chapter+4.+JUnit/4.6+Set+Up+and+Tear+Down/

您可能想知道为什么您应该编写一个setUp()方法,而不是简单地在testing用例的构造函数中初始化字段 。 毕竟,由于为其每个testing方法创build了一个新的testing用例,所以构造函数总是在setUp()之前被调用。 在绝大多数情况下,您可以使用构造函数而不是setUp(),而没有任何副作用。

如果你的testing用例是更深的inheritance层次结构的一部分,你可能希望推迟对象初始化,直到派生[test]类的实例被完全构build 。 这是一个很好的技术原因,您可能想要使用setUp()而不是构造函数来进行初始化。 使用setUp()和tearDown() 对于文档的目的也是很好的,因为它可以使代码更容易阅读

3.在安装失败的情况下更好的诊断

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

在构造函数中设置testing用例不是一个好主意。 …

想象一下[在代码中,在testing用例构造函数中完成设置],在执行设置时,安装程​​序代码会抛出IllegalStateExceptionexception。 作为回应,JUnit会抛出一个AssertionFailedError,表明testing用例不能被实例化。 …

这个[在testing用例构造函数中的设置代码中引发的exception]的堆栈跟踪certificate是非信息化的; 它只是表示testing用例不能被实例化。

不用在构造函数中设置数据,而是通过覆盖setUp()来执行testing设置。 setUp()中引发的任何exception都会正确报告。

这个堆栈跟踪[在setUp()方法而不是testing用例构造函数中引发的exception]更具信息性; 它显示抛出了哪个exception(IllegalStateException)和从哪里。 这使得解释testing设置的失败变得容易得多。

SpringJUnit4ClassRunner这样的自定义运行SpringJUnit4ClassRunner可能需要在构造函数和@Before方法之间运行一些代码。 在这种情况下,跑步者可能会注入@Before方法所需的某些依赖项。 但dependency injection只能在构造对象之后运行。

您需要的原因是,对于许多testing,您经常需要在每次testing之前对状态进行初始化,以便testing可以对所运行的开始状态进行假设。

假设你的testing类包装数据库访问。 在每次testing之后,您都希望删除您的testing对数据库所做的任何更改 – 如果您没有这样做,那么每个testing都会针对稍有修改的数据库运行。 此外,如果以前testing的某些子集失败,则任何给定的testing可能会看到一组不同的更改。 例如,假设test1执行插入操作,test2将检查您是否准确读取了表格大小。 第1天,test1失败,0是正确的。 第2天,test1成功,1是正确的?

顺便说一句,junit也支持@BeforeClass如果你想做一个全局的安装程序,setup和teardowns是可选的。

我觉得有些理由应该是这样的:

  1. 如果将@Before内容移动到构造函数,那很好,但是您可以移动的@After内容?
  2. 构造函数和@ Before / @ After之间的区别是,Constructor应该用来实例化一些类,@之前/ @之后是用于准备testing用例的资源。