轉自: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
本文來自: 中國自學編程網(www.zxbc.cn) 詳細出處參考:http://www.zxbc.cn/html/rjgc/1414044383648.htm