您的位置:軟件測試 > 開源軟件測試 > 開源單元測試工具 > junit
JUnit 5系列之基礎(chǔ)入門介紹
作者:Linesh 發(fā)布時間:[ 2016/9/29 14:32:34 ] 推薦標(biāo)簽:單元測試 Junit

  上周我們剛剛搭建好了 JUnit 5 的環(huán)境,現(xiàn)在我們可以寫測試了。這節(jié)讓我們來寫它幾個吧!
  概述
  本文章是這個 JUnit 5 系列的一部分:
  · 環(huán)境搭建
  · 基礎(chǔ)入門
  · 架構(gòu)體系
  · 擴展模型(Extension Model)
  · 條件斷言
  · 注入
  · 動態(tài)測試
  ...
  (如果不喜歡看文章,你可以戳這里看我的演講,或者看一下近的 vJUG 講座,或者我在 DevoxxPL 上的 PPT。
  本系列文章都基于 Junit 5發(fā)布的先行版 Milestone 2。它可能會有變化。如果有新的里程碑(milestone)版本發(fā)布,或者試用版正式發(fā)行時,我會再來更新這篇文章。
  這里要介紹的多數(shù)知識你都可以在 JUnit 5 用戶指南 中找到(這個鏈接指向的是先行版 Milestone 2,想看的新版本文檔的話請戳這里),并且指南還有更多的內(nèi)容等待你發(fā)掘。下面的所有代碼都可以在 我的 Github 上找到。
  設(shè)計哲學(xué)
  新的架構(gòu)設(shè)計(這個我們?nèi)蘸罅?,其關(guān)注點在高擴展性。如果后面出現(xiàn)了什么神之測試技術(shù)(至少對我們廣大 Java?來說很神的),它們也可能在 JUnit 5 的架構(gòu)下被實現(xiàn)。
  不過當(dāng)前來說,涉及的基礎(chǔ)知識與 JUnit 4 是非常相似的。JUnit 5 的改動并不激進,相反它的優(yōu)化歷程是小心翼翼,小步迭代的。因此,開發(fā)者應(yīng)該會對新的 API 感到非常熟悉。至少我是這樣的,我相信你也不會感覺陌生:
class Lifecycle {
@BeforeAll
static void initializeExternalResources() {
System.out.println("Initializing external resources...");
}
@BeforeEach
void initializeMockObjects() {
System.out.println("Initializing mock objects...");
}
@Test
void someTest() {
System.out.println("Running some test...");
assertTrue(true);
}
@Test
void otherTest() {
assumeTrue(true);
System.out.println("Running another test...");
assertNotEquals(1, 42, "Why wouldn't these be the same?");
}
@Test
@Disabled
void disabledTest() {
System.exit(1);
}
@AfterEach
void tearDown() {
System.out.println("Tearing down...");
}
@AfterAll
static void freeExternalResources() {
System.out.println("Freeing external resources...");
}
}
  是吧?這里并沒有很大的改動。
  JUnit 5 預(yù)備
  包可見性
  JUnit 5 明顯的變化應(yīng)該是,不再需要手動將測試類與測試方法為 public 了。包可見的訪問級別足夠了。當(dāng)然,私有(private)訪問還是不行的。我認為這個變化是合理的,也符合我們對可見性的一般直覺。
  這很好!至少可以少打幾個字母了。不過,我相信你也不是每次都手打這幾個字母的,是吧?盡管如此還是很好,少一些關(guān)鍵字,你在看測試的時候也少些切換。
  測試的生命周期
  @Test
  JUnit 中基本的注解非 @Test 莫屬了。它會標(biāo)記方法為測試方法,以便構(gòu)建工具和 IDE 能夠識別并執(zhí)行它們。
  它的 API 和作用并沒有變化,不過它不再接受任何參數(shù)了。若要測試是否拋出異常,你可以通過新的斷言 API 來做到;不過我所知,目前還沒有超時選項timeout的替代品。
  與 JUnit 4一樣,JUnit 5 會為每個測試方法創(chuàng)建一個新的實例。
  Before 和 After
  你可能需要執(zhí)行一些代碼來在測試執(zhí)行前后完成一些初始化或銷毀的操作。在 JUnit 5 中,有4個注解你可能會用于如此工作:
  @BeforeAll
  只執(zhí)行一次,執(zhí)行時機是在所有測試和 @BeforeEach 注解方法之前。
  @BeforeEach
  在每個測試執(zhí)行之前執(zhí)行。
  @AfterEach
  在每個測試執(zhí)行之后執(zhí)行。
  @AfterAll
  只執(zhí)行一次,執(zhí)行時機是在所有測試和 @AfterEach 注解方法之后。
  因為框架會為每個測試創(chuàng)建一個單獨的實例,在 @BeforeAll/@AfterAll 方法執(zhí)行時尚無任何測試實例誕生。因此,這兩個方法必須定義為靜態(tài)方法。
  注解了同樣一個注解的不同方法,其執(zhí)行次序是不可預(yù)知的,包括對繼承來的方法也適用。這是開發(fā)團隊經(jīng)過審慎思考后的決定,即把單元測試與集成測試的關(guān)注點分開。集成測試可能需要方法間更緊密的協(xié)作,但一個單元測試不應(yīng)該對其他的單元測試有所依賴。而對于集成測試——也叫場景測試——的支持,也已在團隊的計劃中。
  除了名字有所不同,這幾個注解與 JUnit 4 中的注解工作方式完全一樣。無獨有偶,跟主流意見一致,我也覺得這個新的命名不能說服我其必要性。這個 issue 下有更多的討論。
  禁用測試
  今兒星期五,抬頭一看已經(jīng)4點半,無心工作的你想回家了?完全理解,在測試上怒拍一個 @Disabled 注解即可。有良心的話寫個忽略測試的理由是極好的,不過也可以不帶此參數(shù)。
  @Test
  @Disabled("你丫是存心跑不過的是不?!")
  void failingTest() {
  assertTrue(false);
  }
  測試類的生命周期
  JUnit 團隊發(fā)布的第一版原型中,包含了一個對 測試類的生命周期 的描述,有意思的是,這個特性在 alpha 版本的發(fā)布中未被加入。這個生命周期模型建議,在被測類的多個測試方法中使用一個同樣的實例,因為這樣我們可以通過改變對象的狀態(tài),進而實現(xiàn)在多個測試方法中的交互。(我也再說一遍,這更像是 場景測試 要管的事。)
  正如我在第一版公測時所說,這樣的特性99%的場景下是有害的,只有另外1%的場合下才有真正的用處。我只能說,還好這個特性被摒棄了。想想你的單元測試,如果它們必須靠在方法間維護狀態(tài)來工作,這畫面簡直太美我不敢看?。
  斷言
  如果說 @Test、@Before...、@After... 等注解是一個測試套件的骨架,那么斷言是它的心臟。準(zhǔn)備好測試實例、執(zhí)行了被測類的方法以后,斷言能確保你得到了想要的結(jié)果。否則,說明當(dāng)前測試失敗了。
  常規(guī)斷言
  一般的斷言,無非是檢查一個實例的屬性(比如,判空與判非空等),或者對兩個實例進行比較(比如,檢查兩個實例對象是否相等)等。無論哪種檢查,斷言方法都可以接受一個字符串作為后一個可選參數(shù),它會在斷言失敗時提供必要的描述信息。如果提供出錯信息的過程比較復(fù)雜,它也可以被包裝在一個 lambda 表達式中,這樣,只有到真正失敗的時候,消息才會真正被構(gòu)造出來。
@Test
void assertWithBoolean() {
assertTrue(true);
assertTrue(this::truism);
assertFalse(false, () -> "Really " + "expensive " + "message" + ".");
}
boolean truism() {
return true;
}
@Test
void assertWithComparison() {
List<String> expected = asList("element");
List<String> actual = new LinkedList<>(expected);
assertEquals(expected, actual);
assertEquals(expected, actual, "Should be equal.");
assertEquals(expected, actual, () -> "Should " + "be " + "equal.");
assertNotSame(expected, actual, "Obviously not the same instance.");
}
  如你所見,JUnit 5 的 API 并無太多變化。斷言方法的命名是一樣的,方法同樣接受兩個參數(shù),分別是一個期望值與一個實際值。
  期望值與實際值的傳入順序非常重要,無論是對于理解測試的內(nèi)容,還是理解失敗時的錯誤信息,但有時還是很容易弄錯,這點很坑。不過仔細想想,也沒什么更好的辦法,除非你自己創(chuàng)建一個新的斷言框架。既然市面上已有對應(yīng)的產(chǎn)品如 Hamcrest (ugh!) 和AssertJ (yeah!譯者表示:不太清楚這歡呼的梗在哪里)等,再浪費有限的時間去造輪子明顯不值得。畢竟重要的是保證你的斷言庫專注于一件事,借鑒已有實現(xiàn)可以節(jié)省成本。
  哦對了,失敗信息現(xiàn)在是作為后傳入的參數(shù)了。我很喜歡這個細節(jié),因為,它讓你專注于真正重要之事——那兩個需被斷言的值。由于擁抱了 Java 8 的緣故,真值斷言方法現(xiàn)在也接受 supplier 參數(shù)了,又是一個暖心的小細節(jié)。
  擴展斷言
  除了那種一般的檢查特定實例或?qū)傩缘臄嘌酝猓有一些其他類型的斷言。
  這里要講的第一個甚至都不是個真正的斷言,它做的事是強行讓測試失敗,并提供一個失敗信息。
  @Test
  void failTheTest() {
  fail("epicly");
  }

上一頁12下一頁
軟件測試工具 | 聯(lián)系我們 | 投訴建議 | 誠聘英才 | 申請使用列表 | 網(wǎng)站地圖
滬ICP備07036474 2003-2017 版權(quán)所有 上海澤眾軟件科技有限公司 Shanghai ZeZhong Software Co.,Ltd