JUnit简单使用教程
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
JUnit簡(jiǎn)介
???? ??JUnit是由 Erich Gamma和Kent Beck編寫(xiě)的一個(gè)回歸測(cè)試框架(regression testing?framework)。JUnit測(cè)試是程序員測(cè)試,即所謂白盒測(cè)試,因?yàn)槌绦騿T知道被測(cè)試的軟件如何(How)完成功能和完成什么樣(What)的功能。
簡(jiǎn)單編寫(xiě)單元測(cè)試實(shí)例
public class JunitAnnotation {// execute before class@BeforeClasspublic static void beforeClass() {System.out.println("in before class");}// execute after class@AfterClasspublic static void afterClass() {System.out.println("in after class");}// execute before test@Beforepublic void before() {System.out.println("in before");}// execute after test@Afterpublic void after() {System.out.println("in after");}// test case@Testpublic void test() {System.out.println("in test");}// test case ignore and will not execute@Ignore(“unimplemented”)public void ignoreTest() {System.out.println("in ignore test");} }JUnit常用注解介紹
? ? ??@Test:JUnit 3.x是通過(guò)對(duì)測(cè)試方法的命名(test+方法名)來(lái)確定是否是測(cè)試,且所有的測(cè)試類(lèi)必須繼承TestCase。JUnit 4.x只需要在方法前加上@Test 就可以定義一個(gè)測(cè)試方法。
? ? ? 注意:測(cè)試方法必須是public void,即公共、無(wú)返回值的;可以拋出異常。
? ? ??@Ignore :該注解標(biāo)記的測(cè)試方法在測(cè)試中會(huì)被忽略。當(dāng)測(cè)試的方法還沒(méi)有實(shí)現(xiàn),或者測(cè)試的方法已經(jīng)過(guò)時(shí),或者在某種條件下才能測(cè)試該方法(比如需要一個(gè)數(shù)據(jù)庫(kù)連接,而在本地測(cè)試的時(shí)候,數(shù)據(jù)庫(kù)并沒(méi)有連接),那么使用該注解來(lái)標(biāo)記這個(gè)方法。同時(shí)可以為該注解傳遞一個(gè)String的參數(shù),表明為什么會(huì)忽略這個(gè)測(cè)試方法。比如:@lgnore(“該方法還沒(méi)有實(shí)現(xiàn)”),在執(zhí)行的時(shí)候,僅會(huì)報(bào)告該方法沒(méi)有實(shí)現(xiàn),而不會(huì)運(yùn)行測(cè)試方法。
??????@BeforeClass:當(dāng)我們運(yùn)行幾個(gè)有關(guān)聯(lián)的用例時(shí),可能會(huì)在數(shù)據(jù)準(zhǔn)備或其它前期準(zhǔn)備中執(zhí)行一些相同的命令,這個(gè)時(shí)候?yàn)榱俗尨a更清晰,更少冗余,可以將公用的部分提取出來(lái), 放在一個(gè)方法里,并為這個(gè)方法注解@BeforeClass。意思是在測(cè)試類(lèi)里所有用例運(yùn)行之前,運(yùn)行一次這個(gè)方法。例如創(chuàng)建數(shù)據(jù)庫(kù)連接、讀取文件等。
? ? ??注意:方法名可以任意,但必須是public static void,即公開(kāi)的、靜態(tài)的、無(wú)返回值的。這個(gè)方法只會(huì)運(yùn)行一次。
? ? ? @AfterClass:跟@BeforeClass對(duì)應(yīng),在測(cè)試類(lèi)里所有用例運(yùn)行之后,運(yùn)行一次。用于處理一些測(cè)試后續(xù)工作,例如清理數(shù)據(jù),恢復(fù)現(xiàn)場(chǎng)。
? ? ? 注意:同樣必須是public static void,即公開(kāi)的、靜態(tài)的、無(wú)返回值的。這個(gè)方法只會(huì)運(yùn)行一次。
? ? ? @Before:使用了該注解的方法在每個(gè)測(cè)試方法執(zhí)行之前都要執(zhí)行一次。主要用于一些獨(dú)立于用例之間的準(zhǔn)備工作。比如兩個(gè)用例都需要讀取數(shù)據(jù)庫(kù)里的用戶(hù)A信息,但第一個(gè)用例會(huì)刪除這個(gè)用戶(hù)A,而第二個(gè)用例需要修改用戶(hù)A。那么可以用@BeforeClass創(chuàng)建數(shù)據(jù)庫(kù)連接。用@Before來(lái)插入一條用戶(hù)A信息。
? ? ? 注意:必須是public void,不能為static。
? ? ??@After :使用了該注解的方法在每個(gè)測(cè)試方法執(zhí)行之后要執(zhí)行一次。
? ? ? @Runwith:即測(cè)試運(yùn)行器,放在測(cè)試類(lèi)名之前,用來(lái)確定測(cè)試類(lèi)怎么運(yùn)行的,當(dāng)不指定這個(gè)注解時(shí),使用默認(rèn)Runner來(lái)運(yùn)行測(cè)試代碼,即@RunWith(JUnit4.class)。
??????常見(jiàn)的運(yùn)行器有:
? ? ? (1)@RunWith(Parameterized.class):參數(shù)化運(yùn)行器,配合@Parameters使用JUnit的參數(shù)化功能。
? ? ? (2)@RunWith(Suite.class)
? ? ? ? ?@SuiteClasses({ATest.class,BTest.class,CTest.class})
? ? ? ? ??測(cè)試集運(yùn)行器配合使用測(cè)試集功能。????
? ? ? (3)@RunWith(JUnit4.class):JUnit 4的默認(rèn)運(yùn)行器
? ? ??(4)@RunWith(JUnit38ClassRunner.class):用于兼容junit3.8的運(yùn)行器
? ? ? (5)一些其它運(yùn)行器具備更多功能。例如@RunWith(SpringJUnit4ClassRunner.class)集成了Spring的一些功能。
? ? ? @Parameters:用于JUnit的參數(shù)化功能,用來(lái)標(biāo)記準(zhǔn)備數(shù)據(jù)的方法。
? ? ? ?注意:該方法需要滿足一定的要求:?
????????????? (1)該方法必須為public?static的
? ? ? ? ? ? ? (2)該方法返回值必須為java.util.Collection類(lèi)型?
? ? ? ? ? ? ? (3)該方法的名字不做要求?
? ? ? ? ? ? ? (4)該方法沒(méi)有參數(shù)?
參數(shù)化測(cè)試
??????為了保證單元測(cè)試的嚴(yán)謹(jǐn)性,我們模擬了不同的測(cè)試數(shù)據(jù)來(lái)測(cè)試方法的處理能力,為此我們編寫(xiě)了大量的單元測(cè)試方法。而這些測(cè)試方法大同小異:代碼結(jié)構(gòu)都是相同的,不同的僅僅是測(cè)試數(shù)據(jù)和期望值。為了降低代碼的冗余,JUnit 4提供了參數(shù)化測(cè)試,即只寫(xiě)一個(gè)測(cè)試方法,把這若干種情況作為參數(shù)傳遞進(jìn)去,一次性的完成測(cè)試。?
? ? ?JUnit 4參數(shù)化測(cè)試的五個(gè)步驟:
? ? ?(1)為準(zhǔn)備使用參數(shù)化測(cè)試的測(cè)試類(lèi)指定特殊的運(yùn)行器org.junit.runners.Parameterized。
? ? ?(2)為測(cè)試類(lèi)聲明幾個(gè)變量,分別用于存放期望值和測(cè)試所用數(shù)據(jù)。
? ? ?(3)為測(cè)試類(lèi)聲明一個(gè)帶有參數(shù)的公共構(gòu)造函數(shù),并在其中為第二個(gè)環(huán)節(jié)中聲明的幾個(gè)變量賦值。
? ? ?(4)為測(cè)試類(lèi)聲明一個(gè)使用注解 org.junit.runners.Parameterized.Parameters飾的,返回值為java.util.Collection的公共靜態(tài)方法,并在此方法中初始化所有需要測(cè)試的參數(shù)對(duì)。
????(5)編寫(xiě)測(cè)試方法,使用定義的變量作為參數(shù)進(jìn)行測(cè)試。
????Demo如下:
@RunWith(Parameterized.class) public class SquareTest {private static Calculator calculator = new Calculator();private int param;//參數(shù)private int result;//期望值// 準(zhǔn)備數(shù)據(jù) @Parameters public static Collection data() {return Arrays.asList(new Object[][]{{2, 4},{0, 0},{-3, 9}});}//構(gòu)造函數(shù),對(duì)變量進(jìn)行初始化public SquareTest(int param, int result) {this.param = param;this.result = result;}@Test public void square() {calculator.square(param);assertEquals(result, calculator.getResult());}}打包測(cè)試
? ? ? ?在一個(gè)項(xiàng)目中,只寫(xiě)一個(gè)測(cè)試類(lèi)是不可能的,我們會(huì)寫(xiě)出很多很多個(gè)測(cè)試類(lèi)。可是這些測(cè)試類(lèi)必須一個(gè)一個(gè)的執(zhí)行,也是比較麻煩的事情。鑒于此,JUnit為我們提供了打包測(cè)試的功能,將所有需要運(yùn)行的測(cè)試類(lèi)集中起來(lái),一次性的運(yùn)行完畢,大大的方便了我們的測(cè)試工作。具體代碼如下:
@RunWith(Suite.class) @Suite.SuiteClasses({ CalculatorTest.class,SquareTest.class}) public class AllCalculatorTests{ }
? ?? ?大家可以看到,這個(gè)功能也需要使用一個(gè)特殊的Runner,因此我們需要向@RunWith注解傳遞一個(gè)參數(shù)Suite.class。同時(shí),我們還需要另外一個(gè)注解@Suite.SuiteClasses,來(lái)表明這個(gè)類(lèi)是一個(gè)打包測(cè)試類(lèi)。我們把需要打包的類(lèi)作為參數(shù)傳遞給該注解就可以了。有了這兩個(gè)注解之后,就已經(jīng)完整的表達(dá)了所有的含義,因此下面的類(lèi)已經(jīng)無(wú)關(guān)緊要,隨便起一個(gè)類(lèi)名,內(nèi)容全部為空既可。
異常測(cè)試
? ? ? ?在JUnit 4之前,對(duì)錯(cuò)誤的測(cè)試,我們只能通過(guò)fail來(lái)產(chǎn)生一個(gè)錯(cuò)誤,并在try塊里面assertTrue(true)來(lái)測(cè)試。現(xiàn)在,可以通過(guò)@Test 注解中的expected屬性來(lái)測(cè)試異常。expected屬性的值是一個(gè)異常的類(lèi)型。
? ? ? ?Demo如下:
@Test(expected=ArithmeticException.class) public void testDivide() {new Calculator().divide(6, 0); }
限時(shí)測(cè)試
? ? ? 對(duì)于那些邏輯很復(fù)雜,循環(huán)嵌套比較深的程序,很有可能出現(xiàn)死循環(huán),因此一定要采取一些預(yù)防措施。限時(shí)測(cè)試是一個(gè)很好的解決方案。我們給這些測(cè)試方法設(shè)定一個(gè)執(zhí)行時(shí)間,超過(guò)了這個(gè)時(shí)間,他們就會(huì)被系統(tǒng)強(qiáng)行終止,并且系統(tǒng)還會(huì)向你匯報(bào)該方法結(jié)束的原因是因?yàn)槌瑫r(shí),這樣你就可以發(fā)現(xiàn)這些Bug了。要實(shí)現(xiàn)這一功能,只需要給@Test 注解加一個(gè)timeout屬性,該注解傳入了一個(gè)時(shí)間(毫秒)給測(cè)試方法,如果測(cè)試方法在指定的時(shí)間之內(nèi)沒(méi)有運(yùn)行完,則測(cè)試失敗。
? ? ? Demo如下:? ?
@Test(timeout=1000) public void testDeathLoop() {new Calculator().deathLoop(); }
???????? 單元測(cè)試運(yùn)行結(jié)果:java.lang.Exception: test timed out after 1000 milliseconds
???????? at test.Calculator.deathLoop(Calculator.java:25)
???????? at test.CaculatorTest.testDeathLoop(CaculatorTest.java:26)
???????? at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
???????? at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
???????? …………………………
轉(zhuǎn)載于:https://my.oschina.net/jackieyeah/blog/183277
總結(jié)
以上是生活随笔為你收集整理的JUnit简单使用教程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 融资余额是什么意思啊,未还款的融资总金额
- 下一篇: android一些小技巧