转自:http://www.zxbc.cn/html/rjgc/1414044383648.htm
JUnit best practices
JUnit 最佳实践
Techniques for building resilient, relocatable, multithreaded JUnit tests
一项灵活的、可重定位的多线程JUnit测试技术
作者 Andy Schneider
译者 雷云飞 javawebstart Barret gstian [AKA]
校对 gstian [AKA]
Summary
摘要
Extreme Programming's rise in popularity among the Java community has prompted more development teams to use JUnit: a simple test framework for building and executing unit tests. Like any toolkit, JUnit can be used effectively and ineffectively. In this article, Andy Schneider discusses good and bad ways to use JUnit and provides practical recommendations for its use by development teams. In addition, he explains simple mechanisms to support:
Java社区里面流行的编程热的不断升温使越来越多的开发团队使用 JUnit进行测试。JUnit 是一种构造和进行单元测试的简便的测试框架。就象所有的工具包一样,JUnit 可以被高效的使用,也可以被低效的使用。在这篇文章种,Andy Schneider讨论了JUnit 的高效和低效的使用方法,并且为开发团队提供了实用的JUnit使用建议。另外,他提供了几种简单的机制来解释两种方法的差别:
Automatic construction of composite tests
组合测试的自动构件
Multithreaded test cases
多线程测试用例
This article assumes some familiarity with JUnit. (4,000 words)
阅读本篇文章,需要您对JUnit略知一二。
JUnit is a typical toolkit: if used with care and with recognition of its idiosyncrasies, JUnit will help to develop good, robust tests. Used blindly, it may produce a pile of spaghetti instead of a test suite. This article presents some guidelines that can help you avoid the pasta nightmare. The guidelines sometimes contradict themselves and each other -- this is deliberate. In my experience, there are rarely hard and fast rules in development, and guidelines that claim to be are misleading.
JUnit是一个有特色的工具包:熟知它的特性的情况下并细心的使用,它在你开发优良的健壮的测试上市有帮助的。如果被盲目的使用,它可能就像一堆意大利面条,而不是测试集。本文给出了一些可以帮助你避免这些生面团恶梦的指导方针。这些指导方针有时看起来会相互矛盾————这是故意的。以我的经验,在开发中很少有硬性而方便的规则。任何声称是这种规则的指导方针都是误导。
We'll also closely examine two useful additions to the developer's toolkit:
我们同时还将深入检查开发者的工具包里的两个有用的附加物:
A mechanism for automatically creating test suites from classfiles in part of a filesystem
一种可以从部分文件系统里面自动创建测试集的机制
A new TestCase that better supports tests in multiple threads
一种更好支持多线程的新测试用例。
When faced with unit testing, many teams end up producing some kind of testing framework. JUnit, available as open source, eliminates this onerous task by providing a ready-made framework for unit testing. JUnit, best used as an integral part of a development testing regime, provides a mechanism that developers can use to consistently write and execute tests. So, what are the JUnit best practices?
当面对单元测试时,许多团队都会自己去完成某种测试框架。JUnit做为一种开放软件,通过为单元测试提供一种现成的测试框架,来消除这种繁重的任务。JUnit作为一个开发测试体制整体中的一部分给开发者提供了一种可以一致地编写和执行测试的机制。既然如此,那么,什么是JUnit的最佳实践?
Do not use the test-case constructor to set up a test case
不要使用测试用例构造器来创建一个测试用例
Setting up a test case in the constructor is not a good idea. Consider:
使用构造器来建立一个测试用例并不是个好主意,例如:
public class SomeTest extends TestCase
public SomeTest (String testName) {
super (testName);
// Perform test set-up
}
}
Imagine that while performing the setup, the setup code throws an IllegalStateException. In response, JUnit would throw an AssertionFailedError, indicating that the test case could not be instantiated. Here is an example of the resulting stack trace:
想象一下当执行安装时,代码抛出一个IllegalStateException异常。做为回应,JUnit也会抛出一个AssertionFailedError异常来指示测试用例无法实例化。下面是一个堆栈跟踪结果示例:
junit.framework.AssertionFailedError: Cannot instantiate test case: test1 at
junit.framework.Assert.fail(Assert.java:143) at
junit.framework.TestSuite$1.runTest(TestSuite.java:178) at
junit.framework.TestCase.runBare(TestCase.java:129) at
junit.framework.TestResult$1.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.TestRunner$12.run(TestRunner.java:429)
This stack trace proves rather uninformative; it only indicates that the test case could not be instantiated. It doesn't detail the original error's location or place of origin. This lack of information makes it hard to deduce the exception's underlying cause.
这个堆栈跟踪没有提供多少有价值的信息。它只是表明测试用例不能被实例化。它并没有初始化时产生错误的错误位置和错误来源的详细信息。信息的缺乏使得推断该异常出现的原因变得困难。
Instead of setting up the data in the constructor, perform test setup by overriding setUp(). Any exception thrown within setUp() is reported correctly. Compare this stack trace with the previous example:
放弃在构造器中创建数据,通过重载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$1.protect(TestResult.java:100) at
junit.framework.TestResult.runProtected(TestResult.java:117) at
junit.framework.TestResult.run(TestResult.java:103)
...
This stack trace is much more informative; it shows which exception was thrown (IllegalStateException) and from where. That makes it far easier to explain the test setup's failure.
这个堆栈跟踪含有更多的信息量。它表明了异常类型(IllegalStateException), 以及产生位置。这使得可以更容易解释为何测试建立失败。
Don't assume the order in which tests within a test case run
不要推测一个测试用例运行中各测试的执行顺序
You should not assume that tests will be called in any particular order. Consider the following code segment:
你不应该认为各测试用例会按照任何特定顺序被调用。考虑下面的代码片断:
public class SomeTestCase extends TestCase {
public SomeTestCase (String testName) {
super (testName);
}
public void testDoThisFirst () {
...
}
public void testDoThisSecond () {
}
}
In this example, it is not certain that JUnit will run these tests in any specific order when using reflection. Running the tests on different platforms and Java VMs may therefore yield different results, unless your tests are designed to run in any order. Avoiding temporal coupling will make the test case more robust, since changes in the order will not affect other tests. If the tests are coupled, the errors that result from a minor update may prove difficult to find.
在这个例子中,当使用映射时,JUnit将按照何种顺序执行这些测试并不能确定。在不同的平台及Java VM上,可能产生不同的结果,除非你的测试被事先设计为按某种顺序执行。由于执行顺序的改变不会影响其它测试,避免这种短暂的耦合使得你的测试用例更加健壮。如果测试耦合在一起,由于一个小变动引起的错误也许会难于发现。
In situations where ordering tests makes sense -- when it is more efficient for tests to operate on some shared data that establish a fresh state as each test runs -- use a static suite() method like this one to ensure the ordering:
在某些情况下,测试的顺序还是有意义的————例如,测试们可以使用一些共享数据时来提高效率。这些共享数据对于每个测试运行时都会建立一个新的状态。————可以使用一个静态的 suite() 方法来保证执行顺序,如下:
public static Test suite() {
suite.addTest(new SomeTestCase ("testDoThisFirst";));
suite.addTest(new SomeTestCase ("testDoThisSecond";));
return suite;
}
There is no guarantee in the JUnit API documentation as to the order your tests will be called in, because JUnit employs a Vector to store tests. However, you can expect the above tests to be executed in the order they were added to the test suite.
在JUnit API 文档中并没有保证你的测试被调用的顺序,因为JUnit使用V一个区段来存放测试。 然而,你可以保证上面的测试按照它们被加入测试集的顺序被执行。
Avoid writing test cases with side effects
避免写带有副作用的测试用例
Test cases that have side effects exhibit two problems:
带有副作用的测试用例会出现下面两个问题:
They can affect data that other test cases rely upon
它们会影响其他测试用例所依赖的数据
You cannot repeat tests without manual intervention
你不能在没有手工干预的情况下重复测试
In the first situation, the individual test case may operate correctly. However, if incorporated into a TestSuite that runs every test case on the system, it may cause other test cases to fail. That failure mode can be difficult to diagnose, and the error may be located far from the test failure.
在第一种情况下,独立的测试用例也许可以正确的执行,然而,当它们被置入一个执行 该系统中所有测试的测试集时,可能导致其他测试用例失败。但这种失败的做法很难 诊断出来,错误也许离失败的地方很远。
In the second situation, a test case may have updated some system state so that it cannot run again without manual intervention, which may consist of deleting test data from the database (for example). Think carefully before introducing manual intervention. First, the manual intervention will need to be documented. Second, the tests could no longer be run in an unattended mode, removing your ability to run tests over
本文转自博客园执着的笨蛋的博客,原文链接:JUnit best practice,如需转载请自行联系原博主。