JUnit4是一個(gè)易學(xué)易用的Java單元測(cè)試框架,使用非常廣泛?,F(xiàn)階段的最新版本號(hào)是4.12,JUnit5目前正在測(cè)試中,所以這里還是以JUnit4為準(zhǔn)。
引入JUnit
現(xiàn)在主流的IDE比如IDEA或者Eclipse都提供了對(duì)JUnit4的支持,可以非常方便的使用JUnit4。當(dāng)你在代碼中添加了@Test注解,然后使用IDE的自動(dòng)補(bǔ)全功能時(shí),一般情況下IDE會(huì)彈出對(duì)話框詢問(wèn)你是否將JUnit4庫(kù)添加到項(xiàng)目的類路徑下。
當(dāng)然也可以自己手動(dòng)添加JUnit4的依賴。如果使用Maven,添加如下一段:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
如果使用Gradle,添加如下一段:
testCompile group: 'junit', name: 'junit', version: '4.12'
使用以上這些構(gòu)建工具還有一個(gè)好處就是可以指定作用域,在上面我們將JUnit的作用域指定為測(cè)試時(shí)期,也就是說(shuō)當(dāng)我們實(shí)際發(fā)布代碼的時(shí)候并不會(huì)包含JUnit的包。
基本使用
下面演示了JUnit的基本使用方法。
public class AppTest {
private User user;
@Before
public void init() {
user = new User();
user.setId(1);
user.setUsername("yitian");
user.setPassword("1234");
user.setBirthday(LocalDate.now());
}
@Test
public void testBean() {
Assert.assertNotNull(user);
}
}
要讓一個(gè)方法變成測(cè)試方法,只需要向其添加@Test注解即可。在測(cè)試方法中我們可以使用傳統(tǒng)的System.out.println方法來(lái)輸出,也可以使用各種日志框架來(lái)打印日志。還可以使用幾個(gè)注解來(lái)初始化和清理測(cè)試方法用到的數(shù)據(jù)。Before和After注解會(huì)在每個(gè)測(cè)試方法之前和之后調(diào)用。BeforeClass和AfterClass注解會(huì)在所有測(cè)試方法之前和之后調(diào)用。這兩個(gè)方法實(shí)際上是作為靜態(tài)方法使用的,所以初始化的數(shù)據(jù)必須定義為靜態(tài)的。由于名字上可能引起混淆,所以在JUnit5中后兩個(gè)注解重新命名為BeforeEach和AfterEach。
public class AppTest {
private static Connection connection;
@BeforeClass
public static void init() throws SQLException {
connection = DriverManager.getConnection("jdbc:mysql///test");
}
@AfterClass
public static void clean() throws SQLException {
connection.close();
}
@Test
public void testBean() {
Assert.assertNotNull(connection);
}
}
定義好測(cè)試方法之后,就可以測(cè)試了。在IDEA中,直接點(diǎn)擊測(cè)試類旁邊的綠色箭頭即可運(yùn)行。如果在Eclipse中,需要點(diǎn)擊運(yùn)行按鈕,然后選擇作為JUnit運(yùn)行。
斷言
除了在測(cè)試方法中使用輸出語(yǔ)句之外,還可以使用JUnit提供的斷言,來(lái)判斷程序是否符合某個(gè)條件,如果斷言為真,測(cè)試通過(guò),如果斷言為假,測(cè)試失敗。斷言在org.junit.Assert類中,有一組以assert開頭的方法用于斷言測(cè)試,基本上涵蓋了大部分需求。下面列舉幾個(gè)常用的,如果有需要的話可以直接調(diào)用assertFail方法讓斷言直接失敗。
| 斷言方法 | 作用 |
|---|---|
| assertTrue | 真值斷言 |
| assertFalse | 假植斷言 |
| assertEquals | 相等斷言 |
| assertNotEquals | 不等斷言 |
| assertNull | 空值斷言 |
| assertNotNull | 非空值斷言 |
| assertFail | 斷言失敗 |
有了這些斷言,就可以方便地測(cè)試了。我們可以創(chuàng)建一個(gè)對(duì)象,然后調(diào)用這些斷言,將對(duì)象的實(shí)際狀態(tài)和我們的預(yù)期結(jié)果進(jìn)行比較,如果斷言失敗,我們就知道什么地方出現(xiàn)了問(wèn)題。
使用Matchers
除了使用基本的斷言,還可以使用Matchers進(jìn)行更方便自然的測(cè)試。假如我們要測(cè)試一個(gè)字符串是否包含color或者colour。使用普通斷言如下:
assertTrue(responseString.contains("color") || responseString.contains("colour"));
// ==> failure message:
// java.lang.AssertionError:
如果使用Matchers的話就像這樣:
assertThat(responseString, anyOf(containsString("color"), containsString("colour")));
// ==> failure message:
// java.lang.AssertionError:
// Expected: (a string containing "color" or a string containing "colour")
// got: "Please choose a font"
可以看到,不論是語(yǔ)法還是測(cè)試輸出,使用Matcher都更加易讀。JUnit官方還列舉了幾個(gè)例子,從中我們就可以看到使用Matchers的方便之處。
assertThat(x, is(3));
assertThat(x, is(not(4)));
assertThat(responseString, either(containsString("color")).or(containsString("colour")));
assertThat(myList, hasItem("3"));
要使用Matchers,需要使用org.junit.Assert類的assertThat方法,然后將要斷言的對(duì)象和Matcher謂語(yǔ)參數(shù)傳入。又細(xì)心的同學(xué)可能會(huì)發(fā)現(xiàn)如果使用Maven或者Gradle,添加了JUnit的話會(huì)同時(shí)包含另一個(gè)依賴項(xiàng)Hamcrest,這個(gè)包中就定義著大量謂語(yǔ),可以讓我們方便的進(jìn)行測(cè)試。詳細(xì)情況請(qǐng)參見(jiàn)Hamcrest的Java文檔。
忽略測(cè)試
要忽略某個(gè)測(cè)試,只需要在測(cè)試方法上添加Ignore注解,還可以使用一個(gè)可選的字符串說(shuō)明忽略測(cè)試的原因。
@Ignore("Test is ignored as a demonstration")
@Test
public void testSame() {
assertThat(1, is(1));
}
測(cè)試的超時(shí)
針對(duì)可能耗費(fèi)大量時(shí)間的測(cè)試,還可以為測(cè)試設(shè)定一個(gè)時(shí)間,如果超過(guò)該時(shí)間測(cè)試直接失敗。
要為某一個(gè)測(cè)試方法設(shè)定超時(shí),在Test注解時(shí)傳入timeout參數(shù),單位是毫秒:
@Test(timeout=1000)
public void testWithTimeout() {
...
}
要為某個(gè)測(cè)試類中的所有方法設(shè)定超時(shí),需要在測(cè)試類中添加一個(gè)org.junit.rules.Timeout的字段并用@Rule注解。
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
public class HasGlobalTimeout {
public static String log;
private final CountDownLatch latch = new CountDownLatch(1);
@Rule
public Timeout globalTimeout = Timeout.seconds(10); // 10 seconds max per method tested
@Test
public void testSleepForTooLong() throws Exception {
log += "ran1";
TimeUnit.SECONDS.sleep(100); // sleep for 100 seconds
}
@Test
public void testBlockForever() throws Exception {
log += "ran2";
latch.await(); // will block
}
}
與其他框架的集成
這個(gè)特性得益于JUnit的運(yùn)行器機(jī)制,它允許第三方軟件創(chuàng)建運(yùn)行器,以自己的方式運(yùn)行JUnit測(cè)試。如果在一個(gè)普通項(xiàng)目中,我們可以使用IDE提供的運(yùn)行測(cè)試功能來(lái)運(yùn)行測(cè)試,IDE會(huì)為我們生成圖形化的運(yùn)行結(jié)果,用顏色來(lái)區(qū)分測(cè)試的成功與否。如果使用Mavne或Gradle,我們可以使用這些工具提供的測(cè)試命令來(lái)運(yùn)行所有測(cè)試,生成測(cè)試結(jié)果。
Spring也提供了自己的運(yùn)行器。如果在Spring項(xiàng)目中我們可以通過(guò)添加@RunWith注解并使用Spring運(yùn)行器,這樣測(cè)試類就會(huì)運(yùn)行在Spring環(huán)境中,我們可以使用Spring的依賴注入將測(cè)試對(duì)象直接注入到測(cè)試類中。當(dāng)然其他的Spring框架特性也支持。
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@Autowired
private User user;
@Test
public void testBean() {
}
}
以上就是JUnit4 單元測(cè)試框架的一些簡(jiǎn)單使用。詳細(xì)情況可以參見(jiàn)它的官方網(wǎng)站。另外JUnit5已經(jīng)進(jìn)入Milestone版本了,相信正式版也不遠(yuǎn)了。等到JUnit5正式版出來(lái)時(shí),我在為大家介紹新版JUnit的使用方法。
參考資料
https://github.com/junit-team/junit4/wiki/Matchers-and-assertthat
https://github.com/junit-team/junit4/wiki/Ignoring-tests
https://github.com/junit-team/junit4/wiki/Timeout-for-tests