(一)JUnit介紹
1.什么是單元測(cè)試?
單元測(cè)試負(fù)責(zé)對(duì)最小的軟件設(shè)計(jì)單元(模塊)進(jìn)行驗(yàn)證,根據(jù)軟件設(shè)計(jì)文檔中對(duì)模塊功能的描述,對(duì)重要的程序分支進(jìn)行測(cè)試并發(fā)現(xiàn)錯(cuò)誤。
2.什么是單元測(cè)試框架?
對(duì)于單元測(cè)試框架來(lái)講,它主要完成以下幾件事。
提供用例組織與執(zhí)行:測(cè)試用例只有幾條時(shí),可以不考慮用例組織,但是用例達(dá)到成百上千時(shí),大量的測(cè)試用例堆砌在一起,就產(chǎn)生了擴(kuò)展性與維護(hù)性等問(wèn)題
提供豐富的斷言方法:不論是功能測(cè)試,還是單元測(cè)試,在用例執(zhí)行完之后都需要將實(shí)際結(jié)果與預(yù)期結(jié)果相比較(斷言),從而斷定用例是否執(zhí)行通過(guò)。單元測(cè)試框架一般提供豐富的斷言方法。例如:判斷相等/不等、包含/不包含、True/False的斷言方法等
提供豐富的日志:當(dāng)測(cè)試用例執(zhí)行失敗時(shí)能拋出清晰的失敗原因,當(dāng)所有用例執(zhí)行完成后能提供豐富的執(zhí)行結(jié)果。例如,總執(zhí)行時(shí)間、失敗用例數(shù)、成功用例數(shù)等。
從這些特性來(lái)看單元測(cè)試框架的作用是:幫助我們更自動(dòng)化完成測(cè)試,所以,它是自動(dòng)化測(cè)試的基礎(chǔ)。
3.什么是JUnit?
Junit官網(wǎng):http://junit.org/
JUnit是一個(gè)編寫可重復(fù)測(cè)試的簡(jiǎn)單框架。它是單元測(cè)試框架的xUnit架構(gòu)的一個(gè)實(shí)例。
JUnit單元測(cè)試好處:測(cè)試時(shí)可以給每個(gè)方法添加一個(gè)@Test,這樣就可以不在main方法中調(diào)用改來(lái)改去。(方法加了@Test可直接運(yùn)行,可以不定義主方法就可以執(zhí)行了)
給一個(gè)方法單元測(cè)試:
1.給方法加@Test
2.導(dǎo)入junit依賴環(huán)境
或者【Maven安裝Junit】(具體操作參加后續(xù)章節(jié)內(nèi)容)
然后就可以點(diǎn)左邊的綠色按鈕單個(gè)執(zhí)行方法了。
如果執(zhí)行,下面顯示綠色代表成功,紅色代表失?。ㄒ话愣际怯挟惓#?/p>
單元測(cè)試不依賴以System.out.println();一般用斷言操作(此處簡(jiǎn)述,詳細(xì)代碼敘述參考后續(xù)JUnit斷言方法部分的內(nèi)容)。
斷言就是你可能某個(gè)方法寫錯(cuò)(并不指的是真實(shí)的錯(cuò)誤,有可能就是跟你預(yù)期不符合而已),但是Junit
還是執(zhí)行綠色的如下:
importorg.junit.Test;
public class Junit_test {
public static void main(String[] args) {
}
public static int add(int a,int b){
return a-b;
}
@Test
public void test(){
int result=add(1,2);
System.out.println(result); //-1
}
}
就是你調(diào)用add方法(但是返回寫為了-號(hào),而不是+號(hào)),期待返回3,但是返回-1,這就是跟你的預(yù)期不符了,但這是Junit測(cè)試還是綠色,所以所不能用輸出來(lái)評(píng)判對(duì)不對(duì);
所以我們應(yīng)該用斷言:
Assert.assertEquals(期望的結(jié)果,運(yùn)算的結(jié)果);(如果不符合你的預(yù)期,下面就會(huì)報(bào)紅色)(assertEquals是方法重載得選對(duì)參數(shù))
importorg.junit.Assert;
importorg.junit.Test;
public class Junit_test {
public static void main(String[] args) {
}
public static int add(int a,int b){
return a-b;
}
@Test
public void test(){
int result=add(1,2);
Assert.assertEquals(3,result);
}
}
這由于預(yù)期是3,而實(shí)際是-1所以報(bào)錯(cuò)(爆紅)。
(二)JUnit安裝
Junit目前分兩個(gè)版本,Junit4和Junit5,本系列教程打算從Junit4開(kāi)始介紹,最后,再介紹Junit5有哪些新特性
1.IntelliJIDEA安裝Junit
Java開(kāi)發(fā)的同學(xué),推薦使用IntelliJIDEA,推薦閱讀《IntelliJIDEA教程》。
1、下載junit-4.12.jar文件:https://github.com/junit-team/junit4/releases
2、打開(kāi)IntelliJIDEA,菜單欄:File菜單–>PorjectStructure選項(xiàng)–>Dependencies標(biāo)簽–>點(diǎn)擊“+”號(hào)–>Library…–>Java。選擇下載的junit-4.12.jar進(jìn)行添加。
3、以同樣的方式下載和導(dǎo)入hamcrest:https://github.com/hamcrest/JavaHamcrest/releases,否則,你將無(wú)法運(yùn)行Junit單元測(cè)試。
2.Maven安裝Junit
相比較而言,Maven的安裝要簡(jiǎn)單很多,打開(kāi)你Maven項(xiàng)目中的pom.xml文件,添加如下配置:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>

3.IDEA安裝Junit插件
idea中需要下載的單元測(cè)試插件,單擊File ,然后找到Settings進(jìn)行設(shè)置 , 如圖找到插件(Junit Generator)


單擊進(jìn)行安裝,安裝完如下圖二

(三)JUnit編寫單元測(cè)試
1.編寫單元測(cè)試
創(chuàng)建JunitDemo類,編寫第一個(gè)單元測(cè)試用例。
importorg.junit.Test;
importstaticorg.junit.Assert.assertEquals;
publicclassJunitDemo{
@Test
publicvoidmyFirstTest(){
assertEquals(2+2,4);
}
}
@Test用來(lái)注釋一個(gè)普通的方法為一條測(cè)試用例。
assertEquals()方法用于斷言兩個(gè)值是否相關(guān)。
importorg.junit.Test;
importstaticorg.junit.Assert.assertEquals;
publicclassJunitDemo{
@Test
publicvoidmyFirstTest(){
assertEquals(2+2,5);
}
}
通過(guò)測(cè)試可以更好的觀察代碼的運(yùn)行效果,還可以看這個(gè)方法運(yùn)行了多少時(shí)間。當(dāng)在開(kāi)發(fā)過(guò)程中,需要對(duì)某些業(yè)務(wù)進(jìn)行性能調(diào)優(yōu)的時(shí)候,不知道哪個(gè)方法是最好的,就可以編寫測(cè)試類代碼通過(guò)運(yùn)行效果的時(shí)間上去對(duì)比,得到時(shí)間復(fù)雜度,消耗的時(shí)間,從而得到最優(yōu)。
2.測(cè)試功能模塊
創(chuàng)建一個(gè)被測(cè)試類:Count,代碼如下:
publicclassCount{
/**
*計(jì)算并返回兩個(gè)參數(shù)的和
*/
publicintadd(intx,inty){
returnx+y;
}
}
Count類的實(shí)現(xiàn)非常簡(jiǎn)單,看注釋就可以了。
接下來(lái),創(chuàng)建CountTest類,用于測(cè)試Count類。
importstaticorg.junit.Assert.assertEquals;
importorg.junit.Test;
publicclassCountTest{
@Test
publicvoidtestAdd(){
Countcount=newCount();
intresult=count.add(2,2);
assertEquals(result,4);
}
}
new出Count類,調(diào)用add()方法并傳參,通過(guò)assertEquals()斷言返回結(jié)果。
恭喜!你已經(jīng)會(huì)編寫單元測(cè)試了。
(四)JUnit注解
1.JUnit注解(標(biāo)簽)
JUnit注解說(shuō)明:
注解 |
說(shuō)明 |
@Test: |
此處編寫測(cè)試用例的方法,標(biāo)識(shí)一條測(cè)試用例。 |
@Test(timeout=xxx) |
設(shè)置當(dāng)前的測(cè)試方法在一定時(shí)間內(nèi)運(yùn)行完,否則返回錯(cuò)誤 |
@Test(expected=Exception.class) |
設(shè)置當(dāng)前的測(cè)試方法是否有異常拋出,異常類型為Exception.class |
@Ignore: |
注釋掉一個(gè)測(cè)試類或方法,該方法或類不會(huì)被執(zhí)行 |
@Before: |
每一個(gè)測(cè)試方法之前運(yùn)行。 |
@After: |
每一個(gè)測(cè)試方法之后運(yùn)行。 |
@BefreClass |
所有測(cè)試開(kāi)始之前運(yùn)行。在一個(gè)類執(zhí)行之前執(zhí)行一次 |
@AfterClass |
所有測(cè)試結(jié)果之后運(yùn)行。在一個(gè)類執(zhí)行之后執(zhí)行一次 |
2.例子
創(chuàng)建被測(cè)試類Count
public class Count {
/**
* 計(jì)算并返回兩個(gè)參數(shù)的和
*/
public int add(int x, int y) {
return x + y;
}
/**
* 計(jì)算并返回兩個(gè)數(shù)相除的結(jié)果
*/
public int division(int a, int b) {
return a / b;
}
}
創(chuàng)建測(cè)試類CountTest.
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import staticorg.junit.Assert.assertEquals;
public class CountTest {
@Before
public void init() {
System.out.println("init...");
}
@After
public void close() {
System.out.println("close...");
}
//驗(yàn)證超時(shí)
@Test(timeout = 100)
public void testAdd() throws InterruptedException {
Thread.sleep(101);
new Count().add(1, 1);
}
//驗(yàn)證拋出異常
@Test(expected = ArithmeticException.class)
public void testDivision() {
new Count().division(8, 0);
}
//跳過(guò)該條用例
@Ignore
@Test
public void testAdd2() {
int result = Count.add(2, 2);
assertEquals(result, 5);
}
}
雖然爆紅,但是該輸出的輸出,該關(guān)閉的關(guān)閉
(五)JUnit注解之Fixture
繼續(xù)介紹JUnit的注解
什么是Fixture
TestFixture是指一個(gè)測(cè)試運(yùn)行所需的固定環(huán)境,準(zhǔn)確的定義:
ThetestfixtureiseverythingweneedtohaveinplacetoexercisetheSUT
在進(jìn)行測(cè)試時(shí),我們通常需要把環(huán)境設(shè)置成已知狀態(tài)(如創(chuàng)建對(duì)象、獲取資源等)來(lái)創(chuàng)建測(cè)試,每次測(cè)試開(kāi)始時(shí)都處于一個(gè)固定的初始狀態(tài);測(cè)試結(jié)果后需要將測(cè)試狀態(tài)還原,所以,測(cè)試執(zhí)行所需要的固定環(huán)境稱為TestFixture。
JUnit中的Fixture
被測(cè)試類同樣使用上一小節(jié)的Count,創(chuàng)建TestFixture測(cè)試類。
importstaticorg.junit.Assert.*;
importorg.junit.*;
publicclassTestFixture{
//在當(dāng)前測(cè)試類開(kāi)始時(shí)運(yùn)行。
@BeforeClass
publicstaticvoidbeforeClass(){
System.out.println("-------------------beforeClass");
}
//在當(dāng)前測(cè)試類結(jié)束時(shí)運(yùn)行。
@AfterClass
publicstaticvoidafterClass(){
System.out.println("-------------------afterClass");
}
//每個(gè)測(cè)試方法運(yùn)行之前運(yùn)行
@Before
publicvoidbefore(){
System.out.println("=====before");
}
//每個(gè)測(cè)試方法運(yùn)行之后運(yùn)行
@After
publicvoidafter(){
System.out.println("=====after");
}
@Test
publicvoidtestAdd1(){
intresult=newCount().add(5,3);
assertEquals(8,result);
System.out.println("testRuntestadd1");
}
@Test
publicvoidtestAdd2(){
intresult=newCount().add(15,13);
assertEquals(28,result);
System.out.println("testRuntestadd2");
}
}
代碼中的注釋已經(jīng)對(duì)@BeforeClass、@AfterClass、@Before、@After做了說(shuō)明。
至于什么時(shí)候會(huì)用到這些方法跟你具體的業(yè)務(wù)用例有關(guān),如果是WebUI自動(dòng)化測(cè)試,可以把瀏覽器驅(qū)動(dòng)的定義放到@Before中,瀏覽器的關(guān)閉放到@After中。
運(yùn)行結(jié)果如下:
(六)JUnit用例執(zhí)行順序
在運(yùn)行測(cè)試的過(guò)程中,有時(shí)候需要控制用例的執(zhí)行順序。
@FixMethodOrder
JUnit通過(guò)@FixMethodOrder注解來(lái)控制測(cè)試方法的執(zhí)行順序的。@FixMethodOrder注解的參數(shù)是org.junit.runners.MethodSorters對(duì)象,在枚舉類org.junit.runners.MethodSorters中定義了如下三種順序類型:
MethodSorters.JVM
LeavesthetestmethodsintheorderreturnedbytheJVM.NotethattheorderfromtheJVMmayvaryfromruntorun(按照J(rèn)VM得到的方法順序,也就是代碼中定義的方法順序)
MethodSorters.DEFAULT(默認(rèn)的順序)
Sortsthetestmethodsinadeterministic,butnotpredictable,order()(以確定但不可預(yù)期的順序執(zhí)行)
MethodSorters.NAME_ASCENDING
Sortsthetestmethodsbythemethodname,inlexicographicorder,withMethod.toString()usedasatiebreaker(按方法名字母順序執(zhí)行)
例子
具體如何使用,看例子,創(chuàng)建TestRunSequence測(cè)試類。
importorg.junit.FixMethodOrder;
importorg.junit.Test;
importorg.junit.runners.MethodSorters;
//按字母順序執(zhí)行
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
publicclassTestRunSequence{
@Test
publicvoidTestCase1(){
System.out.println("TestCase1");
}
@Test
publicvoidTestCase2(){
System.out.println("TestCase2");
}
@Test
publicvoidTestAa(){
System.out.println("TestAa");
}
}
MethodSorters.NAME_ASCENDING設(shè)置按字母的順序執(zhí)行,所以,TestAa()先被執(zhí)行,雖然它在代碼中是最后一條用例。
運(yùn)行結(jié)果如下:
(七)JUnit斷言方法
JUnit斷言方法
斷言一旦失敗,后面的語(yǔ)句將不會(huì)被執(zhí)行。
**斷言(assertion)**是一種在程序中的一階邏輯(如:一個(gè)結(jié)果為真或假的邏輯判斷式),目的為了表示與驗(yàn)證軟件開(kāi)發(fā)者預(yù)期的結(jié)果——當(dāng)程序執(zhí)行到斷言的位置時(shí),對(duì)應(yīng)的斷言應(yīng)該為真。若斷言不為真時(shí),程序會(huì)中止執(zhí)行,并給出錯(cuò)誤信息。
JUnit為我們提供了一些輔助函數(shù),他們用來(lái)幫助我們確定被測(cè)試的方法是否按照預(yù)期的效果正常工作,通常,把這些輔助函數(shù)稱為斷言。下面我們來(lái)介紹一下JUnit的各種斷言。
Junit 4 斷言方法允許檢查測(cè)試方法的期望結(jié)果值和真實(shí)返回值。Junit的org.junit.Assert類提供了各種斷言方法來(lái)寫junit測(cè)試。這些方法被用來(lái)檢查方法的真實(shí)結(jié)果值和期望值。下列一些有用的斷言方法列表:
匯總(部分?jǐn)嘌孕枰a(bǔ)全小節(jié)內(nèi)容)
方法 |
說(shuō)明 |
assertArrayEquals(expecteds,actuals) |
查看兩個(gè)數(shù)組是否相等。 |
assertEquals(expected,actual) |
查看兩個(gè)對(duì)象是否相等。類似于字符串比較使用的equals()方法。 |
assertNotEquals(first,second) |
查看兩個(gè)對(duì)象是否不相等。 |
assertNull(object) |
查看對(duì)象是否為空。 |
assertNotNull(object) |
查看對(duì)象是否不為空。 |
assertSame(expected,actual) |
查看兩個(gè)對(duì)象的引用是否相等。類似于使用“==”比較兩個(gè)對(duì)象。 |
assertNotSame(unexpected,actual) |
查看兩個(gè)對(duì)象的引用是否不相等。類似于使用“!=”比較兩個(gè)對(duì)象。 |
assertTrue(condition) |
查看運(yùn)行結(jié)果是否為true。 |
assertFalse(condition) |
查看運(yùn)行結(jié)果是否為false。 |
assertThat(actual,matcher) |
查看實(shí)際值是否滿足指定的條件。 |
fail() |
讓測(cè)試失敗。 |
assertEquals
函數(shù)原型:assertEquals([String message],expected,actual)
參數(shù)說(shuō)明:
message是個(gè)可選的消息,假如提供,將會(huì)在發(fā)生錯(cuò)誤時(shí)報(bào)告這個(gè)消息。
expected是期望值,通常都是用戶指定的內(nèi)容。
actual是被測(cè)試的代碼返回的實(shí)際值。
例:assertEquals("equals","1","1");
函數(shù)原型:assertEquals([String message],expected,actual,tolerance)
參數(shù)說(shuō)明:
message是個(gè)可選的消息,假如提供,將會(huì)在發(fā)生錯(cuò)誤時(shí)報(bào)告這個(gè)消息。
expected是期望值,通常都是用戶指定的內(nèi)容。
actual是被測(cè)試的代碼返回的實(shí)際值。
tolerance是誤差參數(shù),參加比較的兩個(gè)浮點(diǎn)數(shù)在這個(gè)誤差之內(nèi)則會(huì)被認(rèn)為是相等的。
例:assertEquals ("yes",5.8,11.0/2.0,0.5);
assertNull 和assertNotNull
函數(shù)原型:assertNull([String message],Object object)
參數(shù)說(shuō)明:
message是個(gè)可選的消息,假如提供,將會(huì)在發(fā)生錯(cuò)誤時(shí)報(bào)告這個(gè)消息。
object是待驗(yàn)證的對(duì)象。
該斷言用來(lái)驗(yàn)證給定的對(duì)象是否為null,假如不為null,則驗(yàn)證失敗。相應(yīng)地,還存在能夠驗(yàn)證非null的斷言:
函數(shù)原型:assertNotNull([String message],Object object)
該斷言用來(lái)驗(yàn)證給定的對(duì)象是否為非null,假如為null,則驗(yàn)證失敗。
例:assertNull("null",null);
assertNotNull("not null",newString());
assertSame 和assertNotSame
函數(shù)原型:assertSame ([String message], expected,actual)
參數(shù)說(shuō)明:
message是個(gè)可選的消息,假如提供,將會(huì)在發(fā)生錯(cuò)誤時(shí)報(bào)告這個(gè)消息。
expected是期望值。
actual是被測(cè)試的代碼返回的實(shí)際值。
該斷言用來(lái)驗(yàn)證expected參數(shù)和actual參數(shù)所引用的是否是同一個(gè)對(duì)象,假如不是,則驗(yàn)證失敗。相應(yīng)地,也存在驗(yàn)證不是同一個(gè)對(duì)象的斷言:
函數(shù)原型:assertNotSame ([String message], expected,actual)
該斷言用來(lái)驗(yàn)證expected參數(shù)和actual參數(shù)所引用的是否是不同對(duì)象,假如所引用的對(duì)象相同,則驗(yàn)證失敗。
例:assertSame("same",2,4-2);
assertNotSame("not same",2,4-3);
assertTrue 和 assertFalse
函數(shù)原型:assertTrue ([String message],Boolean condition)
參數(shù)說(shuō)明:
message是個(gè)可選的消息,假如提供,將會(huì)在發(fā)生錯(cuò)誤時(shí)報(bào)告這個(gè)消息。
condition是待驗(yàn)證的布爾型值。
該斷言用來(lái)驗(yàn)證給定的布爾型值是否為真,假如結(jié)果為假,則驗(yàn)證失敗。當(dāng)然,更有驗(yàn)證為假的測(cè)試條件:
函數(shù)原型:assertFalse([String message],Boolean condition)
該斷言用來(lái)驗(yàn)證給定的布爾型值是否為假,假如結(jié)果為真,則驗(yàn)證失敗。
例:assertTrue("true",1==1);
assertFalse("false",2==1);
Fail
函數(shù)原型:Fail([String message])
參數(shù)說(shuō)明:
message是個(gè)可選的消息,假如提供,將會(huì)在發(fā)生錯(cuò)誤時(shí)報(bào)告這個(gè)消息。
該斷言會(huì)使測(cè)試立即失敗,通常用在測(cè)試不能達(dá)到的分支上(如異常)。
assertThat
assertThat介紹
JUnit 4 結(jié)合 Hamcrest 提供了一個(gè)全新的斷言語(yǔ)法——assertThat。程序員可以只使用 assertThat 一個(gè)斷言語(yǔ)句,結(jié)合 Hamcrest 提供的匹配符,就可以表達(dá)全部的測(cè)試思想
一般匹配符斷言
方法 |
介紹 |
assertThat(“myValue”, allOf(startsWith(“my“), containsString(“Val“))) |
allOf匹配符表明如果接下來(lái)的所有條件必須都成立測(cè)試才通過(guò),相當(dāng)于“與”(&&) |
assertThat(“myValue“, anyOf(startsWith(“foo“), containsString(“Val“))) |
anyOf匹配符表明如果接下來(lái)的所有條件只要有一個(gè)成立則測(cè)試通過(guò),相當(dāng)于“或”( |
assertThat(“myValue“, anything()) |
anything匹配符表明無(wú)論什么條件,永遠(yuǎn)為true |
assertThat(“myValue“, is(“myValue“) ) |
is匹配符表明如果前面待測(cè)的值等于后面給出的值,則測(cè)試通過(guò) |
assertThat(“myValue“, not(“foo“)) |
not匹配符和is匹配符正好相反,表明如果前面待測(cè)的值不等于后面給出的值,則測(cè)試通過(guò) |
字符串相關(guān)匹配符
方法 |
介紹 |
assertThat(“myStringOfNote“, containsString(“ring“)) |
containsString匹配符表明如果測(cè)試的字符串包含子字符串則測(cè)試通過(guò) |
assertThat(“myStringOfNote“, endsWith(“Note“)) |
endsWith匹配符表明如果測(cè)試的字符串以子字符串結(jié)尾則測(cè)試通過(guò) |
assertThat(“myStringOfNote“, startsWith(“my“)) |
startsWith匹配符表明如果測(cè)試的字符串以子字符串開(kāi)始則測(cè)試通過(guò) |
assertThat(“foo“, equalTo(“foo“)) |
equalTo匹配符表明如果測(cè)試的數(shù)據(jù)等于則測(cè)試通過(guò),equalTo可以測(cè)試數(shù)值之間,字符串之間和對(duì)象之間是否相等,相當(dāng)于Object的equals方法 |
assertThat(“Foo“, equalToIgnoringCase(“FOO“)) |
equalToIgnoringCase匹配符表明如果測(cè)試的字符串在忽略大小寫的情況下等于則測(cè)試通過(guò) |
assertThat(“my\tfoo bar“, equalToIgnoringWhiteSpace(“my foo bar“) |
equalToIgnoringWhiteSpace匹配符表明如果測(cè)試的字符串在忽略頭尾的任意個(gè)空格的情況下等于則測(cè)試通過(guò),注意:字符串中的空格不能被忽略 |
數(shù)值相關(guān)匹配符
方法 |
介紹 |
assertThat(1.03, is(closeTo(1.0, 0.03))) |
closeTo匹配符表明如果所測(cè)試的浮點(diǎn)型數(shù)在1.0±0.03范圍之內(nèi)則測(cè)試通過(guò) |
assertThat(2, greaterThan(1)) |
greaterThan匹配符表明如果所測(cè)試的數(shù)值大于1則測(cè)試通過(guò) |
assertThat(1, lessThan(2)) |
lessThan匹配符表明如果所測(cè)試的數(shù)值小于2則測(cè)試通過(guò) |
assertThat(1, greaterThanOrEqualTo(1)) |
greaterThanOrEqualTo匹配符表明如果所測(cè)試的數(shù)值大于等于1則測(cè)試通過(guò) |
assertThat(1, lessThanOrEqualTo(1)) |
lessThanOrEqualTo匹配符表明如果所測(cè)試的數(shù)值小于等于1則測(cè)試通過(guò) |
集合相關(guān)匹配符
方法 |
介紹 |
assertThat(myMap, hasEntry(“bar“, “foo“)) |
hasEntry匹配符表明如果測(cè)試的Map對(duì)象含有一個(gè)鍵值為"bar"對(duì)應(yīng)元素值為"foo"的Entry項(xiàng)則測(cè)試通過(guò) |
ssertThat(Arrays.asList(“foo“, “bar“), hasItem(startsWith(“ba“))) |
hasItem匹配符表明如果測(cè)試的迭代對(duì)象含有元素以ba開(kāi)頭項(xiàng)則測(cè)試通過(guò) |
assertThat(myMap, hasKey(“bar“)) |
hasKey匹配符表明如果測(cè)試的**Map對(duì)象含有鍵值“bar”**則測(cè)試通過(guò) |
assertThat(myMap, hasValue(“foo“)) |
hasValue匹配符表明如果測(cè)試的**Map對(duì)象含有元素值“foo”**則測(cè)試通過(guò) |
例子-assertTrue
關(guān)于斷言方法,我們前面用得最多的是assertEquals,用于斷言兩個(gè)對(duì)象是否相等。這里再介紹一個(gè)assertTrue的使用。
創(chuàng)建AssertTest測(cè)試類(包了含被測(cè)試方法):
import org.junit.*;
import static org.junit.Assert.*;
public class AssertTest {
/**
* 判斷一個(gè)數(shù)是否為素?cái)?shù)
*/
public static Boolean Prime(int n) {
for (int i = 2; i < Math.sqrt(n); i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
@Test
public void testPrime() {
int n = 7;
assertTrue(AssertTest.Prime(n));
}
}
Prime()方法用于判斷一個(gè)數(shù)是否為素?cái)?shù)(只能被1和它本身整除的數(shù)),并返回True或False,在測(cè)試用例中通過(guò)assertTrue來(lái)斷言結(jié)果。
例子2 – 多個(gè)斷言的示例
import org.junit.Test;
import org.junit.jupiter.api.DisplayName;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import staticorg.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import staticorg.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import staticorg.junit.jupiter.api.Assertions.assertNotNull;
import staticorg.junit.jupiter.api.Assertions.assertNotSame;
import staticorg.junit.jupiter.api.Assertions.assertNull;
import staticorg.junit.jupiter.api.Assertions.assertSame;
import staticorg.junit.jupiter.api.Assertions.*;
/**
*@author javatutorials.co.in
*/
public class AssertionsTest {
@Test
@DisplayName("assertArrayEquals Examples")
public void test_assertArrayEquals() {
String[] s1 = {"A", "B"};
String[] s2 = {"A", "B"};
assertArrayEquals(s1, s2);
assertArrayEquals("My Custom Failure Message", s1, s2);
}
@Test
@DisplayName("assertIterableEquals Examples")
public void test_assertIterableEquals() {
List<String> l1 = newArrayList<>(Arrays.asList("A", "B"));
List<String> l2 = newLinkedList<>(Arrays.asList("A", "B"));
assertIterableEquals(l1, l2);
assertIterableEquals(l1, l2, "Custom Failure Message");
}
@Test
public void testAssertEqualsLong() {
long long1 = 2;
long long2 = 2;
assertEquals(long1, long2);
}
@Test
public void testAssertEqualsDouble() {
// test case is successfull as double1 and double 2
// differ by 0.001 which is less than our specified delta
double double1 = 1.236;
double double2 = 1.237;
double delta = 0.002;
assertEquals(double1, double2, delta);
}
@Test
@DisplayName("assertEquals Examples")
public void test_assertEquals() {
assertEquals(10, 10);
assertEquals("assertEquals Failure Message", true, true);
assertEquals("Hi", new String("Hi"));
assertEquals(new File("test"), new File("test"));
}
@Test
@DisplayName("assertNotEquals Examples")
public void test_assertNotEquals() {
assertNotEquals(10, 100);
assertNotEquals("assertEquals Failure Message", true, false);
assertNotEquals("Hi", new String("Hello"));
assertNotEquals(new File("test"), newFile("test1"));
}
@Test
public void testAssertNull() {
String str = null;
assertNull(str);
}
@Test
public void testAssertNotNull() {
String str = "hello Java!!";
assertNotNull(str);
}
@Test
@DisplayName("assertNull Examples")
publicvoid test_assertNull() {
assertNull(null);
//assertNull(new Object(), "assertNull Fail Message");
}
@Test
@DisplayName("assertNotNull Examples")
public void test_assertNotNull() {
assertNotNull(new Object());
//assertNotNull(null, "assertNotNull Fail Message");
}
@Test
public void testAssertSame() {
String str1 = "hello world!!";
String str2 = "hello world!!";
assertSame(str2, str1);
}
@Test
public void testAssertNotSame() {
String str1 = "hello world!!";
String str3 = "hello Java!!";
assertNotSame(str1, str3);
}
@Test
@DisplayName("assertSame Examples")
public void test_assertSame() {
assertSame("Hi", "Hi");
// this will fail
// assertSame("Hi", new String("Hi"), "MyFailure Message");
}
@Test
@DisplayName("assertNotSame Examples")
public void test_assertNotSame() {
assertNotSame("Hi", "Hello");
// this will fail
//assertNotSame("Hi", "Hi", "assertNotSameFailure Message");
}
@Test
public void testAssertTrue() {
List<String> list = new ArrayList<String>();
assertTrue(list.isEmpty());
}
@Test
public void testAssertFalse() {
List<String> list = new ArrayList<String>();
list.add("hello");
assertFalse(list.isEmpty());
}
@Test
@DisplayName("assertTrue Examples")
public void test_assertTrue() {
assertTrue(3 > 0);
assertTrue("assertTrue fail message", 3 > 0);
}
@Test
@DisplayName("assertFalse Examples")
public void test_assertFalse() {
assertFalse(3 < 0);
assertFalse("assertFalse fail message", 3 < 0);
}
@Test
@DisplayName("This will Fail, don't worry!")
public void test_fail() {
fail();
fail("Not yet implemented");
}
@Test
@DisplayName("assertThrows Examples")
public void test_assertThrows() {
assertThrows(RuntimeException.class, () -> {
throw new RuntimeException();
});
assertThrows(Exception.class, () -> {
throw new RuntimeException();
});
// this will fail
// assertThrows(IOException.class, () -> {throw newRuntimeException();});
// assertThrows(IOException.class, () -> {throw newRuntimeException();}, "assertThrows Failure Message");
}
}
例子3-assertThat
Cs.java
importjava.util.ArrayList;
importjava.util.HashMap;
importjava.util.List;
importjava.util.Map;
public class Cs{
public int add(int a, int b) {
return a + b;
}
public double div(double a, double b) {
return a / b;
}
public String getName(String name) {
return name;
}
public List<String> getList(Stringitem) {
List<String> l = newArrayList<String>();
l.add(item);
return l;
}
public Map<String, String>getMap(String key, String value) {
Map<String, String> m = newHashMap<String, String>();
m.put(key, value);
return m;
}
}
CsTest.java
importorg.junit.Test;
importjava.util.List;
importjava.util.Map;
import staticorg.hamcrest.MatcherAssert.assertThat;
import staticorg.hamcrest.Matchers.*;
public classCsTest {
@Test
public void testAdd() {
//一般匹配符
int s = new Cs().add(1, 1);
//allOf:所有條件必須都成立,測(cè)試才通過(guò)
assertThat(s, allOf(greaterThan(1),lessThan(3)));
//anyOf:只要有一個(gè)條件成立,測(cè)試就通過(guò)
assertThat(s, anyOf(greaterThan(1),lessThan(1)));
//anything:無(wú)論什么條件,測(cè)試都通過(guò)
assertThat(s, anything());
//is:變量的值等于指定值時(shí),測(cè)試通過(guò)
assertThat(s, is(2));
//not:和is相反,變量的值不等于指定值時(shí),測(cè)試通過(guò)
assertThat(s, not(1));
//數(shù)值匹配符
double d = new Cs().div(10, 3);
//closeTo:浮點(diǎn)型變量的值在3.0±0.5范圍內(nèi),測(cè)試通過(guò)
assertThat(d, closeTo(3.0, 0.5));
//greaterThan:變量的值大于指定值時(shí),測(cè)試通過(guò)
assertThat(d, greaterThan(3.0));
//lessThan:變量的值小于指定值時(shí),測(cè)試通過(guò)
assertThat(d, lessThan(3.5));
//greaterThanOrEuqalTo:變量的值大于等于指定值時(shí),測(cè)試通過(guò)
assertThat(d,greaterThanOrEqualTo(3.3));
//lessThanOrEqualTo:變量的值小于等于指定值時(shí),測(cè)試通過(guò)
assertThat(d, lessThanOrEqualTo(3.4));
//字符串匹配符
String n = new Cs().getName("Magci");
//containsString:字符串變量中包含指定字符串時(shí),測(cè)試通過(guò)
assertThat(n,containsString("ci"));
//startsWith:字符串變量以指定字符串開(kāi)頭時(shí),測(cè)試通過(guò)
assertThat(n,startsWith("Ma"));
//endsWith:字符串變量以指定字符串結(jié)尾時(shí),測(cè)試通過(guò)
assertThat(n, endsWith("i"));
//euqalTo:字符串變量等于指定字符串時(shí),測(cè)試通過(guò)
assertThat(n,equalTo("Magci"));
//equalToIgnoringCase:字符串變量在忽略大小寫的情況下等于指定字符串時(shí),測(cè)試通過(guò)
assertThat(n,equalToIgnoringCase("magci"));
//equalToIgnoringWhiteSpace:字符串變量在忽略頭尾任意空格的情況下等于指定字符串時(shí),測(cè)試通過(guò)
assertThat(n,equalToIgnoringWhiteSpace(" Magci "));
//集合匹配符
List<String> l = newCs().getList("Magci");
//hasItem:Iterable變量中含有指定元素時(shí),測(cè)試通過(guò)
assertThat(l,hasItem("Magci"));
Map<String, String> m = newCs().getMap("mgc", "Magci");
//hasEntry:Map變量中含有指定鍵值對(duì)時(shí),測(cè)試通過(guò)
assertThat(m, hasEntry("mgc","Magci"));
//hasKey:Map變量中含有指定鍵時(shí),測(cè)試通過(guò)
assertThat(m, hasKey("mgc"));
//hasValue:Map變量中含有指定值時(shí),測(cè)試通過(guò)
assertThat(m, hasValue("Magci"));
}
}
(八)JUnit測(cè)試批量運(yùn)行
前面測(cè)試用例的運(yùn)行主要針對(duì)單個(gè)測(cè)試類進(jìn)行的,當(dāng)然,在IntelliJIDEA中也可以選擇單個(gè)的方法執(zhí)行。那如果我們想運(yùn)行所有的用例的文件呢?
IntelliJIDEA中設(shè)置運(yùn)行
設(shè)置
在IntelliJIDEA中,菜單欄:Run菜單–>EditConfigurations…選項(xiàng)。
在Junit目錄下,選擇任意一個(gè)用例文件。
TestKind:選擇用例的運(yùn)行類型/級(jí)別。
packages:選擇用例運(yùn)行的目錄,即你的測(cè)試用例目錄。
設(shè)置完成后,點(diǎn)擊“OK”按鈕。
運(yùn)行
點(diǎn)擊IntelliJIDEA工具欄上的運(yùn)行按鈕,來(lái)運(yùn)行test目錄下的所有用例。
運(yùn)行結(jié)果:
通過(guò)測(cè)試套件運(yùn)行
這種方法引入一種 “測(cè)試套件” 的概念,JUnit 提供了一種批量運(yùn)行測(cè)試類的方法,叫測(cè)試套件。
測(cè)試套件的寫法需要遵循以下原則:
創(chuàng)建一個(gè)空類作為測(cè)試套件的入口;
使用注解 org.junit.runner.RunWith 和 org.junit.runners.Suite.SuitClasses 修飾這個(gè)空類。
將 org.junit.runners.Suite 作為參數(shù)傳入給注解 RunWith,以提示 JUnit 為此類測(cè)試使用套件運(yùn)行器執(zhí)行。
將需要放入此測(cè)試套件的測(cè)試類組成數(shù)組作為注解SuiteClasses 的參數(shù)。
保證這個(gè)空類使用public修飾,而且存在公開(kāi)的不帶任何參數(shù)的構(gòu)造函數(shù)。
單獨(dú)創(chuàng)建一個(gè)測(cè)試類 runAllTest .
package test;
importorg.junit.runner.RunWith;
importorg.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({
CountTest.class,
TestFixture.class,
AssertTest.class,
TestRunSequence.class,
})
public classrunAllTest {
}
把需要運(yùn)行的測(cè)試類放到 SuiteClasses 中,運(yùn)行runAllTest 測(cè)試類,即可批量執(zhí)行測(cè)試用例。
(九)JUnit5 介紹與安裝
官方網(wǎng)址:http://junit.org/junit5/
Junit5 已經(jīng)不算是新的版本了,2016 年推出非正式版,相比較 JUnit4 安裝和使用都有一定的差異。
JUnit5 介紹
The new major version of the programmer-friendly testingframework for Java 8
一個(gè)新的重要版本,程序員更友好的測(cè)試框架,基于 Java8。
關(guān)于
JUnit5 是 JUnit 的下一代。我們的目標(biāo)是為 JVM 上的開(kāi)發(fā)人員端測(cè)試創(chuàng)建一個(gè)最新的基礎(chǔ)。這包括針對(duì) Java 8 及以上,以及使許多不同風(fēng)格的測(cè)試。
Junit5 組成
先看來(lái)個(gè)公式:
JUnit 5 = JUnitPlatform + JUnit Jupiter + JUnit Vintage
這看上去比 Junit4 復(fù)雜,實(shí)際上在導(dǎo)入包時(shí)也會(huì)復(fù)雜一些。
JUnitPlatform 是在JVM上啟動(dòng)測(cè)試框架的基礎(chǔ)。
JUnitJupiter 是JUnit5擴(kuò)展的新的編程模型和擴(kuò)展模型,用來(lái)編寫測(cè)試用例。Jupiter子項(xiàng)目為在平臺(tái)上運(yùn)行Jupiter的測(cè)試提供了一個(gè)TestEngine(測(cè)試引擎)。
JUnitVintage 提供了一個(gè)在平臺(tái)上運(yùn)行JUnit3 和JUnit4 的TestEngine 。
Maven 安裝
首先,你需要通過(guò) IntelliJ?IDEA創(chuàng)建一個(gè) Maven 項(xiàng)目,IntelliJ?IDEA 集成的有 Maven,所以,你很容易做到這一點(diǎn)。通過(guò) Maven 的 pom.xml 文件,添加 Junit5 。
pom.xml 文件配置如下:
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>4.12.1</version>
<scope>test</scope>
</dependency>
</dependencies>
(十)JUnit5 創(chuàng)建測(cè)試
創(chuàng)建測(cè)試用例
我在 IntelliJ?IDEA 中創(chuàng)建的 Maven 項(xiàng)目,目錄結(jié)構(gòu)如下:
SHAPE \* MERGEFORMAT
在 test.java 目錄下創(chuàng)建一個(gè) FistJUnit5Tests 類。代碼如下:
importorg.junit.jupiter.api.Test;
import staticorg.junit.jupiter.api.Assertions.assertEquals;
class FirstJUnit5Tests {
@Test
void myFirstTest() {
assertEquals(2, 1 + 1);
}
}
明顯看出和 Junit4 還是有些不同的。
首先,導(dǎo)入測(cè)試測(cè)試注解(@Test)和斷言方法(assertEquals)的路徑不同。
其次,不需要手動(dòng)把測(cè)試和測(cè)試方法聲明為 public 了。
(十一)JUnit5 新的用法
創(chuàng)建 JUnit5NewTests 測(cè)試類。
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
class JUnit5NewTests {
@BeforeEach
@DisplayName("每條用例開(kāi)始時(shí)執(zhí)行")
void start(){
}
@AfterEach
@DisplayName("每條用例結(jié)束時(shí)執(zhí)行")
void end(){
}
@Test
void myFirstTest() {
assertEquals(2, 1+ 1);
}
@Test
@DisplayName("描述測(cè)試用例╯°□°)╯")
voidtestWithDisplayName() {
}
@Test
@Disabled("這條用例暫時(shí)跑不過(guò),忽略!")
void myFailTest(){
assertEquals(1,2);
}
@Test
@DisplayName("運(yùn)行一組斷言")
public voidassertAllCase() {
assertAll("groupAssert",
() ->assertEquals(2, 1 + 1),
() ->assertTrue(1 > 0)
);
}
@Test
@DisplayName("依賴注入1")
public voidtestInfo(final TestInfo testInfo) {
System.out.println(testInfo.getDisplayName());
}
@Test
@DisplayName("依賴注入2")
public voidtestReporter(final TestReporter testReporter) {
testReporter.publishEntry("name", "Alex");
}
}
用法都已經(jīng)通過(guò)測(cè)試用例的 @DisplayName 進(jìn)行了說(shuō)明,這里不再解釋。
運(yùn)行結(jié)果如下:
(十二)補(bǔ)充:JUnit 注解之Rule
一個(gè)JUnit Rule就是一個(gè)實(shí)現(xiàn)了TestRule的類,這些類的作用類似于 @Before、@After,是用來(lái)在每個(gè)測(cè)試方法的執(zhí)行前后執(zhí)行一些代碼的一個(gè)方法。 那為什么不直接用這些 @Before、@After呢?這是因?yàn)樗鼈兌贾荒茏饔糜谝粋€(gè)類,如果同一個(gè)setup需要在兩個(gè)類里面同時(shí)使用,那么你就要在兩個(gè)測(cè)試類里面定義相同的@Before方法,然后里面寫相同的代碼,這就造成了代碼重復(fù)。
此外,JUnit Rule還能做一些 @Before、@After這些注解做不到的事情,那就是他們可以動(dòng)態(tài)的獲取將要運(yùn)行的測(cè)試類、測(cè)試方法的信息。
使用框架自帶的Rule
除了增加Rule特性,新版JUnit還添加了很多核心Rule
TemporaryFolder:測(cè)試可以創(chuàng)建文件與目錄并且會(huì)在測(cè)試運(yùn)行結(jié)束后將其刪除。這對(duì)于那些與文件系統(tǒng)打交道且獨(dú)立運(yùn)行的測(cè)試來(lái)說(shuō)很有用。
ExternalResource:這是一種資源使用模式,它會(huì)提前建立好資源并且會(huì)在測(cè)試結(jié)束后將其銷毀。這對(duì)于那些使用socket、嵌入式服務(wù)器等資源的測(cè)試來(lái)說(shuō)很有用。
ErrorCollector:可以讓測(cè)試在失敗后繼續(xù)運(yùn)行并在測(cè)試結(jié)束時(shí)報(bào)告所有錯(cuò)誤。這對(duì)于那些需要驗(yàn)證大量獨(dú)立條件的測(cè)試來(lái)說(shuō)很有用(盡管這本身可能是個(gè)“test smell”)。
ExpectedException:可以在測(cè)試中指定期望的異常類型與消息。
Timeout:為類中的所有測(cè)試應(yīng)用相同的超時(shí)時(shí)間。
例如,TimeOut這個(gè)Rule的使用。
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
public class RuleTestDemo {
//使用Timeout這個(gè)Rule
@Rule
public Timeout timeout= new Timeout(1000);
@Test
public voidtestMethod1() throws Exception {
Thread.sleep(1001);
}
@Test
public voidtestMethod2() throws Exception {
Thread.sleep(999);
}
}
使用JUnit所提供的Timeout類,該類用于控制測(cè)試用例的執(zhí)行超時(shí)時(shí)間。這里設(shè)置為1秒,當(dāng)用例執(zhí)行超過(guò)1秒則失敗。接下來(lái)分別在 testMethod1和testMethod2兩個(gè)用例中使用sleep()方法來(lái)控制用例的執(zhí)行時(shí)間,顯然testMethod1超過(guò)1秒,則運(yùn)行失敗。
自定義的Rule(沒(méi)跑通)
除了可以使用JUnit框架自帶的Rule,還可以根據(jù)自己的需求自定義Rule。簡(jiǎn)單來(lái)說(shuō),自定義一個(gè)Rule就是implement一個(gè)TestRule 接口,并實(shí)現(xiàn)apply()方法。該方法需要返回一個(gè)Statement對(duì)象。例子如下:
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
public class MethodNameRule implementsTestRule {
public Statement apply(final Statement base, final Descriptiondescription) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
//在測(cè)試方法運(yùn)行之前做一些事情,在base.evaluate()之前
String className =description.getClassName();
String methodName =description.getMethodName();
base.evaluate(); //運(yùn)行測(cè)試方法
//在測(cè)試方法運(yùn)行之后做一些事情,在base.evaluate()之后
System.out.println("Classname:"+className+", method name: "+methodName);
}
};
}
}
這里實(shí)現(xiàn)的功能是在每次測(cè)試用例運(yùn)行之后,打印當(dāng)前測(cè)試用例的類名和方法名。 在上面的例子中添加這里定義的MethodNameRule。
……文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-753848.html
public class RuleTestDemo {
//使用Timeout這個(gè)Rule
@Rule
public Timeout timeout = new Timeout(1000);
//使用自定義Rule,
@Rule
public MethodNameRule methodNameRule = new MethodNameRule();
……
再次運(yùn)行測(cè)試用例,執(zhí)行結(jié)果如下:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-753848.html
到了這里,關(guān)于詳解JUnit單元測(cè)試框架(打樁測(cè)試待更新)示例代碼有格式問(wèn)題,待更新的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!