junit4新特性-測試必備利器
junit4新特性-測試必備利器
Junit4更新的版本很多,現在已經更新到4.10了。發生的變化也相當的明顯,為了更好的使用測試,有必要去學習一下其新的功能。
總的來說,其變化還是比較多的。
於是整合,收集了一些網友的文章。綜合起來看還是算比較完整了,更多的只有自己去探討了,不過常用的已經夠用。
junit4給我的印像:
1,你的方法不必以test開頭命名,你可以在你喜歡的任何地方進行測試,前提是你有@Test在這個方法前註釋。
2,加入的很多機制,比如Assumption(假設機制)等等。
3,加入了不少測試方法,比如數組測試,assertEquals(Object[] expected, Object[] actual)
4,套件測試,可以幾個類一起進行測試,非常強大。
總之,它更多的是引進的不少註解的方法,比以前方便比如@Ignore可以忽略此方法, @Test(timeout=1)//測試運行時間 (單位:millisecond)
它不是junit3的升級,完全是另外一種版本。
更多詳細看看下面的:
一、以下來源於:http://zhan.zhmy.com/archives/2006/79054.html
JUnit 是JAVA語言事實上的標準測試庫。JUnit 4是三年以來最具里程碑意義的一次發布。它的新特性主要是針對JAVA5中的標記(annotation)來簡化測試,而不是利用子類、反射或命名機制。本文將講述如何使用JUnit 4,當前提是你最好具有JUnit的使用經驗.
JUnit, 由Kent Beck?和 Erich Gamma開發,幾乎是JAVA開發最重要的第三方工具。正如Martin Fowler 所說,「在軟體開發領域,從來就沒有如此少的代碼起到了如此重要的作用「。由於JUnit,JAVA代碼變得更健壯,更可靠,BUG也比以前更少。由於JUnit (由Smalltalk's的SUnit得來) 的出現,隨後產生了許多xUnit的測試工具,如nUnit (.NET), pyUnit (Python), CppUnit (C++), dUnit (Delphi) 和其它不同平台及語言的測試相關的工具。
雖然JUnit也只是一個工具,但其產生的思想和技術卻較其架構更意義重大。單元測試,測試先行的編程方式,測試驅動的開發方式,並非必須由JUNIT實現,也不一定要用SWing實現GUI界面。JUNIT最近的一次更新是在三年前,但它比其它大多數有BUG的框架都要健壯,更重要的是,JAVA一直在改進。現在JAVA支持泛型,枚舉,可變長度參數,以及標記語言(開創了開發可重用框架的新局面)。
JUnit's的停滯不前使得那些想要變革的開發人員換其它測試工具.挑戰者有Bill Venners的Artima SuiteRunner和Cedric Beust的TestNG.這些工具庫雖然有值得推薦的功能,但沒有任何一款的地位能與JUNIT相比,沒有任何一款工具被其它業界產品如Ant, Maven, Eclipse廣泛支持.因此Beck 和Gamma雙開始利用JAVA5的新特性來開發新版的JUNIT,目的是利用JAVA5中的標記特性使得單元測試開發更容易。Beck說:「JUNIT4的主要目的是通過簡化JUNIT的使用鼓勵更多的開發人員寫更多的測試」。雖然會與以前的版本兼容,但JUNIT4與從JUNIT1.0就開始的版本相比會有一個非常大的變化.
注意: 修改基本框架是一把雙刃劍,雖然JUNIT4的目的是清晰的,但細節仍有許多不同,因此本文只是一個簡單的介紹,並不是最終文檔.
測試方法
在JUNIT 4中,測試方法由@Test 標記說明,如下:
import org.junit.Test; import junit.framework.TestCase; public class AdditionTest extends TestCase { private int x = 1; private int y = 1; @Test public void testAddition() { int z = x + y; assertEquals(2, z); } }使用標記的好處是你不用將所有測試方法命名為 testFoo(),testBar()等等以"test"開頭的方法。
這種命名機制最大的優點是更適合你的待測試類或方法名稱,例如,你可以使用ListTEst.contains()測試List.contains();使用ListTest.addAll()測試List.add()等等.
TestCase還可以繼續使用,但你沒有必須再擴展為子類,只要你聲明了@Test,你可以將測試方法放在任何類中,當然如要訪問assert等方法,你必須要引用junit.Assert類,如下:import org.junit.Assert;
public class AdditionTest {
private int x = 1;
private int y = 1;
@Test
public void addition() {
int z = x + y;
Assert.assertEquals(2, z);
}
}你也可以使用JDK5中的新特性(static import)使得跟以前版本一樣簡單:
import static org.junit.Assert.assertEquals;
public class AdditionTest {
private int x = 1;
private int y = 1;
@Test
public void addition() {
int z = x + y;
assertEquals(2, z);
}
}這種方法測試受保護的方法非常容易,因為你可以在測試類中繼承有受保護方法的類.
SetUp 和TearDown
在JUnit 4中,你仍然可以在每個測試前初始化變數和配置環境,,然而,這些操作可以不用在Setup()中完成,你可以在初始化方法前面添加@Beforer 來表示,如下:@Before
protected void initialize() {
System.setErr(new PrintStream(new ByteArrayOutputStream()));
inputDir = new File("data");
inputDir = new File(inputDir, "xslt");
inputDir = new File(inputDir, "input");
}你也可以有多個方法標記有@Before,所有方法都會在每個測試之前執行。
清除環境與JUNIT3 差不多,在JUNIT3中使用tearDown()方法。在JUnit4中,你還可以使用@After標記來說明:@After
protected void disposeDocument() {
doc = null;
System.gc();
}與 @Before一樣,你也可以有多個標記有 @After的清除方法,每個都會在執行完每個測試后執行。
最後,你不需要在父類中明確調用這些初始化或清除方法.test runner會自動調用這些標記的方法.子類中的@Before方法在父類的@Before方法之後執行(這與構造函數的執行順序一樣),而@After方法剛好相反,子類中的@After方法先執行.然而,多個@Before和@After方法的執行順序就是未知的.
測試集範圍的初始化
JUnit 4中引入了一項JUNIT3沒有的新特性,類級別的setUp()和tearDown(),即在一個類的所有測試前執行初始化,並在所有測試完成後執行清除。
例如,一個測試類中的每個測試都要用到一個資料庫連接或網路連接,或其它很耗資源初始化或釋放的資源,用不著在每個測試方法前後進行操作,而只需要在測試類開始前後執行即可。下面的示例是使用第三方的庫進行錯誤,在執行所有測試前將錯誤先重定向到非標準輸出,然後在所有測試結束后再輸出到需要的地方,這樣就不會影響到測試過程中產生的其它信息。// This class tests a lot of error conditions, which
// Xalan annoyingly logs to System.err. This hides System.err
// before each test and restores it after each test.
private PrintStream systemErr;
@BeforeClass
protected void redirectStderr() {
systemErr = System.err; // Hold on to the original value
System.setErr(new PrintStream(new ByteArrayOutputStream()));
}
@AfterClass
protected void tearDown() {
// restore the original value
System.setErr(systemErr);
}上面的操作沒有必須在每個測試前後執行。然而要注意的是,這種方法可能影響測試間的結果,如果一個測試改變了初始化的對象,而這個對象可能是其它測試的輸入,那麼測試的結果可能不正確,這種方法將依賴測試的順序並可能引入BUG。當優化測試性能,並且當你改進了配置和基準測試后而仍然很慢時,如資料庫連接或網路問題,你才需要考慮使用這種方法。只有這樣,你才能每天執行多次測試。
異常測試
異常測試是JUNIT4中的最大的改進,以前異常測試是通過try catch實現,當拋出異常時,在try的最後添加一條fail()語句實現.如下:public void testDivisionByZero() {
try {
int n = 2 / 0;
fail("Divided by zero!");
}
catch (ArithmeticException success) {
assertNotNull(success.getMessage());
}
}這種方法不僅難看,而且造成無論成功或失敗,代碼覆蓋工具都不能執行某些代碼.而在JUnit 4中,你可以在要拋出異常的代碼中添加標記來聲明一個異常是期望的:@Test(expected=ArithmeticException.class)
public void divideByZero() {
int n = 2 / 0;
}如果沒有異常拋出,上面的測試則會失敗,如果你想知道異常的詳細信息或其它情況,你還是要使用try catch才行。
時間測試
性能測試是單元測試中最頭疼的問題,JUnit 4也未完全解決此問題, 你可以在JUNIT4的測試方法中添加一個時間參數。如果測試時間超過參數,則測試失敗。如下,如果測試時間超過0.5秒,則此測試失敗:@Test(timeout=500)
public void retrieveAllElementsInDocument() {
doc.query("//*");
} 新的斷言
JUnit 4 增加了兩上斷文方法用於比較數組:
public static void assertEquals(Object[] expected, Object[] actual)
public static void assertEquals(String message, Object[] expected, Object[] actual)
這兩個方法採用最直接方法比較,如果數組長度相同,且每個對應的元素相同,則比較成功,否則不成功.參數為空的情況也作了考慮.
需要補充的地方
JUnit 4是一個非常基本的框架,還不是以前版本的升級。JUNIT3的開發人員會發現有些功能沒有。
最大的特點就是沒有GUI測試界面,當測試正確時是綠色條,而出錯時紅色的,你也可以在Eclipse中集成JUNIT使用,但JUNIT4既沒有AWT也沒有SWING的GUI測試界面;
另一個讓人吃驚的是失敗(期望錯誤)和錯誤(未預計的異常錯誤)沒有明顯區別,在JUNIT3中開發人員可以區分這兩種情況,而在JUNIT4中不行;
最後一個特點是JUNIT中沒有用於建立一堆測試類的suite()方法,取而代之的是,採用變長參數傳遞未知數量的測試給test runner。
沒有GUI測試界面的確不方便,但其它改變簡化了JUNIT的使用,從當前JUNIT的操作手冊和FAQ的數量就知道,而JUNIT4的文檔將不會需要這麼多
二、以下來源於:http://fansofjava.iteye.com/blog/503709
下面列舉一些改變之處:
1. 測試由原來的命名模式改變註解,即testXXX變為@Test。其中@Test還提供了額外的屬性。如expected,表示期望拋出的異常,用法如下:
Java代碼 view plaincopy
[email protected](expected = NullPointerException.class)
public void unsupportedDBCheck() {
throw new NullPointerException();
}
@Test(expected = NullPointerException.class)
public void unsupportedDBCheck() {
throw new NullPointerException();
} 由於上面得到期望拋出的異常,所以測試通過。
2. 數組比較改用Assert.assertArrayEquals
3. 套件測試也用註解替換,如下如示:
Java代碼 view
[email protected](Suite.class)
@SuiteClasses({
Hello.class,
TheoryTest.class
})
public class SuiteClassesTest {
}
@RunWith(Suite.class)
@SuiteClasses({
Hello.class,
TheoryTest.class
})
public class SuiteClassesTest {
} 4. 通過@Ignore,可以忽略某個方法或整個類的測試
5. 增加了新特性-理論機制(Theory),這個特性聽起來很迷惑人,作用是使得開發人員從開始的定義測試用例的階段就可以通過參數集(理論上是無限個參數)對代碼行為進行概括性的總結.開發人員都知道他們代碼所想要實現的概括性的總的目的,理論使得他們只需要在一個地方就可以快速的指定這些目的,而不要將這些目的翻譯成大量的獨立的測試用例。用法如下所示:
Java代碼 view
[email protected](Theories.class)
public class TheoryTest {
@DataPoint public static String name ="theories";
@DataPoint public static String password = "2009";
@Theory
public void outNameAndPassword(String name,String password){
System.out.println("name="+name+" password="+password);
}
}
@RunWith(Theories.class)
public class TheoryTest {
@DataPoint public static String name ="theories";
@DataPoint public static String password = "2009";
@Theory
public void outNameAndPassword(String name,String password){
System.out.println("name="+name+" password="+password);
}
} 輸出為:
引用
name=theories password=theories
name=theories password=2009
name=2009 password=theories
name=2009 password=2009
也就是說,方法的參數與定義的欄位會把所有的組合情況全部考慮進去,雖然用到此特性的地方不多,但有時的確很有用。這樣也不用逐個寫斷言語句,把測試數據集中在一個地方,方便管理。
6. 提供了新的特性-假設機制(Assumption).此特性使用了Hamcrest庫的類.本來Hamcrest是一個單獨的測試組件,Junit也集成了一部分,但是並沒有完全包含。建議使用junit獨立的JAR文件,再單獨引入hamcrest包。
其實hamcrest的功能相當的強大,理解起來也非常的容易,是一個很不錯的組件。不過好像並沒發現其參考文檔。它提供assertThat,assumeThat,assumeNotNull等假設語句,也提供is,not,both..and,either..or等用法,非常的靈活。如:Java代碼 view plaincopyprint?//斷言"yy"不等於"xx"
assertThat("yy", is(not("xx")));
//abcdefg包含adcd或fsd
assertThat("abcdefg",anyOf(containsString("abcd"),containsString("fsd")));
//斷言"yy"不等於"xx"
assertThat("yy", is(not("xx")));
//abcdefg包含adcd或fsd
assertThat("abcdefg",anyOf(containsString("abcd"),containsString("fsd"))); 其中assumeXXX的目的為,假設此條件成立,才執行後面的語句,否則跳出些測試方法,繼續執行其它的測試。如:
Java代碼 view plaincopyprint?//如果此假設語句不成立,則不會列印出this is assumeAssume.assumeThat(4,both(lessThanOrEqualTo(6)).and(greaterThan(3)));
System.out.println("this is assume");
//如果此假設語句不成立,則不會列印出this is assume
Assume.assumeThat(4,both(lessThanOrEqualTo(6)).and(greaterThan(3)));
System.out.println("this is assume"); 7. @Before,@After,@BeforeClass,@AfterClass.這幾個註解一看便知大概,@Before表示每個測試方法執行前執行一次,而@BeforeClass表示整個類測試前執行一次。不過需要注意的是,@BeforeClass,@AtferClass註解的方法必須是靜態的。
8. Junit提供了新的核心運行類MaxCore,相對於以前的JunitCore運行機制,這個類有一系列的優點,如從未測試過的方法優先測試,剩下的測試中,以前測試失敗的方法優先測試,再其次,運行快的優先於運行慢的方法。用法如官方例子如示:
Java代碼 view plaincopyprint?public static class TwoUnEqualTests {
@Test
public void slow() throws InterruptedException {
Thread.sleep(100);
fail();
}
@Test
public void fast() {
fail();
}
}
@Test
public void rememberOldRuns() {
File maxFile = new File("history.max");
MaxCore firstMax = MaxCore.storedLocally(maxFile);
firstMax.run(TwoUnEqualTests.class);
MaxCore useHistory= MaxCore.storedLocally(maxFile);
List
failures= useHistory.run(TwoUnEqualTests.class)
.getFailures();
assertEquals("fast", failures.get(0).getDescription().getMethodName());
assertEquals("slow", failures.get(1).getDescription().getMethodName());
}
public static class TwoUnEqualTests {
@Test
public void slow() throws InterruptedException {
Thread.sleep(100);
fail();
}
@Test
public void fast() {
fail();
}
}
@Test
public void rememberOldRuns() {
File maxFile = new File("history.max");
MaxCore firstMax = MaxCore.storedLocally(maxFile);
firstMax.run(TwoUnEqualTests.class);
MaxCore useHistory= MaxCore.storedLocally(maxFile);
List failures= useHistory.run(TwoUnEqualTests.class)
.getFailures();
assertEquals("fast", failures.get(0).getDescription().getMethodName());
assertEquals("slow", failures.get(1).getDescription().getMethodName());
} 當然這個替代也是相對的,有時候還是可以繼續用JUnitCore,MaxCore只是在JUnitCore基礎上增加優先測試之類的規則,但是有些功能還是需要用JUnitCore。比如說,如果想在eclipse中不通過junit插件來運行單元測試,就需要JUnitCore:
Java代碼 view plaincopyprint?public class ObjectToClassTest {
@Test
public void ObjectTest(){
int[] a={1,2};
int[] b={1,2};
Assert.assertArrayEquals(a,b);
}
public static void main(String[] args){
JUnitCore.main("com.junit.ObjectToClassTest");
}
}
public class ObjectToClassTest {
@Test
public void ObjectTest(){
int[] a={1,2};
int[] b={1,2};
Assert.assertArrayEquals(a,b);
}
public static void main(String[] args){
JUnitCore.main("com.junit.ObjectToClassTest");
}
} 當然這種方式針對的是類,不能限制到方法上,如果有多個類,只需要用空格把類隔開即可。
上面基本包含了Junit4.6之前的新特性,至於以後的新特性,會花專門的篇幅來講解。
《解決方案》
謝謝分享