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

  還有 assertAll 方法,它接受可變數(shù)量的斷言作為參數(shù),并保證它們?nèi)康玫綀?zhí)行,然后再把錯(cuò)誤信息(如果有)一并匯報(bào)出來。
  @Test
  void assertAllProperties() {
  Address address = new Address("New City", "Some Street", "No");
  assertAll("address",
  () -> assertEquals("Neustadt", address.city),
  () -> assertEquals("Irgendeinestra?e", address.street),
  () -> assertEquals("Nr", address.number)
  );
  }
  org.opentest4j.MultipleFailuresError: address (3 failures)
  expected: <Neustadt> but was: <New City>
  expected: <Irgendeinestra?e> but was: <Some Street>
  expected: <Nr> but was: <No>
  這個(gè)特性在檢查對象的多個(gè)屬性值時(shí)非常有用。按照一般的做法,測試在第一個(gè)斷言失敗時(shí)會掛掉了,此時(shí)只有第一個(gè)出錯(cuò)的地方得到提示,而你無法得知其他值的斷言是否成功,只好再跑一遍測試。
  后,我們終于有了 assertThrows 和 expectThrows 方法。兩者均會在被測方法未拋出預(yù)期異常時(shí)失敗。而后者還會返回拋出的異常實(shí)例,以用于后續(xù)的驗(yàn)證,比如,斷言異常信息包含正確的信息等。
  @Test
  void assertExceptions() {
  assertThrows(Exception.class, this::throwing);
  Exception exception = expectThrows(Exception.class, this::throwing);
  assertEquals("Because I can!", exception.getMessage());
  }
  假言/判定(Assumptions)
  假言/判定允許你僅在特定條件滿足時(shí)才運(yùn)行測試。這個(gè)特性能夠減少測試組件的運(yùn)行時(shí)間和代碼重復(fù),特別是在假言都不滿足的情況下。
@Test
void exitIfFalseIsTrue() {
assumeTrue(false);
System.exit(1);
}
@Test
void exitIfTrueIsFalse() {
assumeFalse(this::truism);
System.exit(1);
}
private boolean truism() {
return true;
}
@Test
void exitIfNullEqualsString() {
assumingThat(
"null".equals(null),
() -> System.exit(1)
);
}
  假言/判定適用于兩種情形,要么是你希望在某些條件不滿足時(shí)中止測試,要么是你希望僅當(dāng)某個(gè)條件滿足時(shí)才執(zhí)行(部分)測試。主要的區(qū)別是,被中止的測試是以被禁用(disabled)的形式被報(bào)告,此時(shí)沒有測試任何內(nèi)容,因?yàn)闂l件得不到滿足。
  測試嵌套
  在 JUnit 5 中,嵌套測試幾乎不費(fèi)吹灰之力。你只需要在嵌套的類上添加 @Nested 注解,類中的所有方法即會被引擎執(zhí)行:
package org.codefx.demo.junit5;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
class Nest {
int count = Integer.MIN_VALUE;
@BeforeEach
void setCountToZero() {
count = 0;
}
@Test
void countIsZero() {
assertEquals(0, count);
}
@Nested
class CountGreaterZero {
@BeforeEach
void increaseCount() {
count++;
}
@Test
void countIsGreaterZero() {
assertTrue(count > 0);
}
@Nested
class CountMuchGreaterZero {
@BeforeEach
void increaseCount() {
count += Integer.MAX_VALUE / 2;
}
@Test
void countIsLarge() {
assertTrue(count > Integer.MAX_VALUE / 2);
}
}
}
}
  如你所見,嵌套類中的 @BeforeEach(及 @AfterEach )注解也工作良好。不過,構(gòu)造順序似乎還未被寫入文檔,它們的初始化次序是從外向內(nèi)的。這也讓你能疊加式地為內(nèi)部類準(zhǔn)備測試數(shù)據(jù)。
  如果嵌套的內(nèi)部測試想要存取外部測試類的字段,那么嵌套類本身不應(yīng)該是靜態(tài)的。但這樣一來也禁止了靜態(tài)方法的使用,因而這種場景下@BeforeAll 和 @AfterAll 方法也無法使用了(還是說終有他法實(shí)現(xiàn)?)
  你可能有疑惑,嵌套的內(nèi)部測試類有什么用。個(gè)人而言,我用內(nèi)部類來漸進(jìn)測試接口,其他人則多用于保持測試類短小專注。后者同時(shí)也有一個(gè)經(jīng)典的例子來說明,例子由 JUnit 團(tuán)隊(duì)提供,它測試了一個(gè)棧:
class TestingAStack {
Stack<Object> stack;
boolean isRun = false;
@Test
void isInstantiatedWithNew() {
new Stack<Object>();
}
@Nested
class WhenNew {
@BeforeEach
void init() {
stack = new Stack<Object>();
}
// some tests on 'stack', which is empty
@Nested
class AfterPushing {
String anElement = "an element";
@BeforeEach
void init() {
stack.push(anElement);
}
// some tests on 'stack', which has one element...
}
}
}
  在上面的例子中,棧的狀態(tài)改變會反映到內(nèi)層的測試類中,其中內(nèi)部類又基于自身的場景執(zhí)行了一些測試。
  測試命名
  JUnit 5 提供了一個(gè)注解 @DisplayName,它用以為開發(fā)者提供更可讀的測試類和測試方法信息。
  上面的 stack 測試?yán)蛹由显撟⒔庖院笞兂蛇@樣:
@DisplayName("A stack")
class TestingAStack {
@Test
@DisplayName("is instantiated with new Stack()")
void isInstantiatedWithNew() { /*...*/ }
@Nested
@DisplayName("when new")
class WhenNew {
@Test
@DisplayName("is empty")
void isEmpty() { /*...*/ }
@Test
@DisplayName("throws EmptyStackException when popped")
void throwsExceptionWhenPopped() { /*...*/ }
@Test
@DisplayName("throws EmptyStackException when peeked")
void throwsExceptionWhenPeeked() { /*...*/ }
@Nested
@DisplayName("after pushing an element")
class AfterPushing {
@Test
@DisplayName("it is no longer empty")
void isEmpty() { /*...*/ }
@Test
@DisplayName("returns the element when popped and is empty")
void returnElementWhenPopped() { /*...*/ }
@Test
@DisplayName(
"returns the element when peeked but remains not empty")
void returnElementWhenPeeked(){ /*...*/ }
}
}
}
  這是一份TDDer 看了會感動,BDDer 看了會流淚的測試結(jié)果輸出。

  回顧
  差不多這些了,恭喜你終于讀完了。我們匆匆過完了 JUnit 5 的基本特性,現(xiàn)在,你應(yīng)該了解了所有寫測試的必備知識了:包括如何為方法添加生命周期注解(@[Before|After][All|Each]、如何注解測試方法本身(@Test)、如何嵌套測試(@Nested)、如何給測試一個(gè)好信息(@DisplayName),你也應(yīng)該能了解斷言和假言判定是如何工作的了(基本上與前版無異)。
  不過這可還沒完!我們還沒聊到 測試方法的條件執(zhí)行,沒聊到非?岬 參數(shù)注入 ,以及 JUnit 5 的擴(kuò)展機(jī)制 和 架構(gòu)體系 呢。放心,這真的是后了,這些話題我們會一個(gè)月后再聊,現(xiàn)在你可以先休息一下啦。

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