JUnit 4 簡介

JUnit4是一個(gè)易學(xué)易用的Java單元測試框架,使用非常廣泛⊙绯ィ現(xiàn)階段的最新版本號(hào)是4.12叼旋,JUnit5目前正在測試中,所以這里還是以JUnit4為準(zhǔn)。

引入JUnit

現(xiàn)在主流的IDE比如IDEA或者Eclipse都提供了對JUnit4的支持灾炭,可以非常方便的使用JUnit4茎芋。當(dāng)你在代碼中添加了@Test注解,然后使用IDE的自動(dòng)補(bǔ)全功能時(shí)蜈出,一般情況下IDE會(huì)彈出對話框詢問你是否將JUnit4庫添加到項(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的作用域指定為測試時(shí)期燕刻,也就是說當(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è)方法變成測試方法卵洗,只需要向其添加@Test注解即可请唱。在測試方法中我們可以使用傳統(tǒng)的System.out.println方法來輸出,也可以使用各種日志框架來打印日志过蹂。還可以使用幾個(gè)注解來初始化和清理測試方法用到的數(shù)據(jù)十绑。Before和After注解會(huì)在每個(gè)測試方法之前和之后調(diào)用。BeforeClass和AfterClass注解會(huì)在所有測試方法之前和之后調(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);
    }
}

定義好測試方法之后,就可以測試了击胜。在IDEA中亏狰,直接點(diǎn)擊測試類旁邊的綠色箭頭即可運(yùn)行。如果在Eclipse中潜的,需要點(diǎn)擊運(yùn)行按鈕骚揍,然后選擇作為JUnit運(yùn)行。

斷言

除了在測試方法中使用輸出語句之外啰挪,還可以使用JUnit提供的斷言信不,來判斷程序是否符合某個(gè)條件,如果斷言為真亡呵,測試通過抽活,如果斷言為假,測試失敗锰什。斷言在org.junit.Assert類中下硕,有一組以assert開頭的方法用于斷言測試丁逝,基本上涵蓋了大部分需求。下面列舉幾個(gè)常用的梭姓,如果有需要的話可以直接調(diào)用assertFail方法讓斷言直接失敗霜幼。

斷言方法 作用
assertTrue 真值斷言
assertFalse 假植斷言
assertEquals 相等斷言
assertNotEquals 不等斷言
assertNull 空值斷言
assertNotNull 非空值斷言
assertFail 斷言失敗

有了這些斷言,就可以方便地測試了誉尖。我們可以創(chuàng)建一個(gè)對象罪既,然后調(diào)用這些斷言,將對象的實(shí)際狀態(tài)和我們的預(yù)期結(jié)果進(jìn)行比較铡恕,如果斷言失敗琢感,我們就知道什么地方出現(xiàn)了問題。

使用Matchers

除了使用基本的斷言探熔,還可以使用Matchers進(jìn)行更方便自然的測試驹针。假如我們要測試一個(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"

可以看到诀艰,不論是語法還是測試輸出柬甥,使用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方法捉捅,然后將要斷言的對象和Matcher謂語參數(shù)傳入。又細(xì)心的同學(xué)可能會(huì)發(fā)現(xiàn)如果使用Maven或者Gradle虽风,添加了JUnit的話會(huì)同時(shí)包含另一個(gè)依賴項(xiàng)Hamcrest棒口,這個(gè)包中就定義著大量謂語,可以讓我們方便的進(jìn)行測試辜膝。詳細(xì)情況請參見Hamcrest的Java文檔无牵。

忽略測試

要忽略某個(gè)測試,只需要在測試方法上添加Ignore注解厂抖,還可以使用一個(gè)可選的字符串說明忽略測試的原因茎毁。

@Ignore("Test is ignored as a demonstration")
@Test
public void testSame() {
    assertThat(1, is(1));
}

測試的超時(shí)

針對可能耗費(fèi)大量時(shí)間的測試,還可以為測試設(shè)定一個(gè)時(shí)間忱辅,如果超過該時(shí)間測試直接失敗七蜘。

要為某一個(gè)測試方法設(shè)定超時(shí),在Test注解時(shí)傳入timeout參數(shù)墙懂,單位是毫秒:

@Test(timeout=1000)
public void testWithTimeout() {
  ...
}

要為某個(gè)測試類中的所有方法設(shè)定超時(shí)橡卤,需要在測試類中添加一個(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測試柜与。如果在一個(gè)普通項(xiàng)目中,我們可以使用IDE提供的運(yùn)行測試功能來運(yùn)行測試嵌灰,IDE會(huì)為我們生成圖形化的運(yùn)行結(jié)果弄匕,用顏色來區(qū)分測試的成功與否。如果使用Mavne或Gradle沽瞭,我們可以使用這些工具提供的測試命令來運(yùn)行所有測試粘茄,生成測試結(jié)果。

Spring也提供了自己的運(yùn)行器秕脓。如果在Spring項(xiàng)目中我們可以通過添加@RunWith注解并使用Spring運(yùn)行器柒瓣,這樣測試類就會(huì)運(yùn)行在Spring環(huán)境中,我們可以使用Spring的依賴注入將測試對象直接注入到測試類中吠架。當(dāng)然其他的Spring框架特性也支持芙贫。

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
    @Autowired
    private User user;
    @Test
    public void testBean() {
    }

}

以上就是JUnit4 單元測試框架的一些簡單使用。詳細(xì)情況可以參見它的官方網(wǎng)站傍药。另外JUnit5已經(jīng)進(jìn)入Milestone版本了磺平,相信正式版也不遠(yuǎn)了。等到JUnit5正式版出來時(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市俱诸,隨后出現(xiàn)的幾起案子菠劝,更是在濱河造成了極大的恐慌,老刑警劉巖睁搭,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赶诊,死亡現(xiàn)場離奇詭異,居然都是意外死亡园骆,警方通過查閱死者的電腦和手機(jī)舔痪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锌唾,“玉大人锄码,你說我怎么就攤上這事∩翁椋” “怎么了滋捶?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長渐排。 經(jīng)常有香客問我炬太,道長,這世上最難降的妖魔是什么驯耻? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任亲族,我火速辦了婚禮炒考,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘霎迫。我一直安慰自己斋枢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布知给。 她就那樣靜靜地躺著瓤帚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪涩赢。 梳的紋絲不亂的頭發(fā)上戈次,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機(jī)與錄音筒扒,去河邊找鬼怯邪。 笑死,一個(gè)胖子當(dāng)著我的面吹牛花墩,可吹牛的內(nèi)容都是我干的悬秉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼冰蘑,長吁一口氣:“原來是場噩夢啊……” “哼和泌!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起祠肥,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤武氓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后搪柑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體聋丝,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年工碾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片百姓。...
    茶點(diǎn)故事閱讀 39,711評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡渊额,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出垒拢,到底是詐尸還是另有隱情旬迹,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布求类,位于F島的核電站奔垦,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏尸疆。R本人自食惡果不足惜椿猎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一惶岭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧犯眠,春花似錦雌团、人聲如沸篇裁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽毁枯。三九已至,卻和暖如春法褥,著一層夾襖步出監(jiān)牢的瞬間卖氨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工残炮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留韭赘,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓吉殃,卻偏偏與公主長得像辞居,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子蛋勺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容