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 } }
想象一下,执行安装程序时,安装程序代码会抛出
IllegalStateException
exception。 作为回应,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运行得更快,并为您节省很多头疼!
希望你从我们的错误中学习:)
这里有三个很好的原因。 综上所述:
-
在某些情况下,可能希望尽可能延迟设置testing夹具,直到执行testing用例。
-
一些testing用例可能是深度testing用例inheritance层次结构的一部分。 推迟设置testing夹具,直到构造函数完整的层次结构完成为止。
-
如果安装程序代码在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是可选的。
我觉得有些理由应该是这样的:
- 如果将@Before内容移动到构造函数,那很好,但是您可以移动的@After内容?
- 构造函数和@ Before / @ After之间的区别是,Constructor应该用来实例化一些类,@之前/ @之后是用于准备testing用例的资源。