日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

junit单元测试断言_简而言之,JUnit:单元测试断言

發(fā)布時間:2023/12/3 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 junit单元测试断言_简而言之,JUnit:单元测试断言 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

junit單元測試斷言

簡而言之,本章涵蓋了各種單元測試聲明技術(shù)。 它詳細(xì)說明了內(nèi)置機(jī)制, Hamcrest匹配器和AssertJ斷言的優(yōu)缺點 。 正在進(jìn)行的示例擴(kuò)大了主題,并說明了如何創(chuàng)建和使用自定義匹配器/斷言。

單元測試斷言

信任但要驗證
羅納德·里根(Ronald Reagan)

后期測試結(jié)構(gòu)解釋了為什么單元測試通常分階段進(jìn)行。 它澄清說, 真正的測試即結(jié)果驗證在第三階段進(jìn)行。 但是到目前為止,我們只看到了一些簡單的示例,主要使用了JUnit的內(nèi)置機(jī)制。

如Hello World所示,驗證基于錯誤類型AssertionError 。 這是編寫所謂的自檢測試的基礎(chǔ)。 單元測試斷言將謂詞評估為true或false 。 如果為false ,則拋出AssertionError 。 JUnit運行時捕獲此錯誤并將測試報告為失敗。

以下各節(jié)將介紹三種較流行的單元測試斷言變體。

斷言

JUnit的內(nèi)置斷言機(jī)制由類org.junit.Assert 。 它提供了兩種靜態(tài)方法來簡化測試驗證。 以下代碼片段概述了可用方法模式的用法:

fail(); fail( "Houston, We've Got a Problem." );assertNull( actual ); assertNull( "Identifier must not be null.",actual );assertTrue( counter.hasNext() ); assertTrue( "Counter should have a successor.",counter.hasNext() );assertEquals( LOWER_BOUND, actual ); assertEquals( "Number should be lower bound value.", LOWER_BOUND,actual );
  • Assert#fail()無條件地引發(fā)斷言錯誤。 這對于標(biāo)記不完整的測試或確保引發(fā)了預(yù)期的異常很有幫助(另請參見“ 測試結(jié)構(gòu)”中的“預(yù)期異常”部分)。
  • Assert#assertXXX(Object)用于驗證變量的初始化狀態(tài)。 為此,存在兩個稱為assertNull(Object)和assertNotNull(Object) 。
  • Assert#assertXXX(boolean)方法測試boolean參數(shù)傳遞的預(yù)期條件。 調(diào)用assertTrue(boolean)期望條件為true ,而assertFalse(boolean)期望相反。
  • Assert#assertXXX(Object,Object)和Assert#assertXXX(value,value)方法用于對值,對象和數(shù)組進(jìn)行比較驗證。 盡管結(jié)果沒有區(qū)別,但通常的做法是將期望值作為第一個參數(shù),將實際值作為第二個參數(shù)。
  • 所有這些類型的方法都提供帶有String參數(shù)的重載版本。 如果發(fā)生故障,此參數(shù)將合并到斷言錯誤消息中。 許多人認(rèn)為這有助于更清楚地指定失敗原因。 其他人則認(rèn)為此類消息混亂,使測試更難閱讀。

    乍一看,這種單元測試斷言似乎很直觀。 這就是為什么我在前面的章節(jié)中使用它進(jìn)行入門的原因。 此外,它仍然非常流行,并且工具很好地支持故障報告。 但是,在需要更復(fù)雜的謂詞的斷言的表達(dá)性方面也受到一定限制。

    Hamcrest

    Hamcrest是一個旨在提供用于創(chuàng)建靈活的意圖表達(dá)的API的庫。 該實用程序提供了稱為Matcher的可嵌套謂詞。 這些允許以某種方式編寫復(fù)雜的驗證條件,許多開發(fā)人員認(rèn)為比布爾運算符更易于閱讀。

    MatcherAssert類支持單元測試斷言。 為此,它提供了靜態(tài)的assertThat(T, Matcher )方法。 傳遞的第一個參數(shù)是要驗證的值或?qū)ο蟆?第二個謂詞用于評估第一個謂詞。

    assertThat( actual, equalTo( IN_RANGE_NUMBER ) );

    如您所見,匹配器方法模仿自然語言的流程以提高可讀性。 以下代碼片段更加清楚了此意圖。 這使用is(Matcher )方法來修飾實際的表達(dá)式。

    assertThat( actual, is( equalTo( IN_RANGE_NUMBER ) ) );

    MatcherAssert.assertThat(...)存在另外兩個簽名。 首先,有一個采用布爾參數(shù)而不是Matcher參數(shù)的變量。 它的行為與Assert.assertTrue(boolean) 。

    第二個變體將一個附加的String傳遞給該方法。 這可以用來提高故障消息的表達(dá)能力:

    assertThat( "Actual number must not be equals to lower bound value.", actual, is( not( equalTo( LOWER_BOUND ) ) ) );

    在失敗的情況下,給定驗證的錯誤消息如下所示:

    Hamcrest帶有一組有用的匹配器。 圖書館在線文檔的“常見匹配項”部分中列出了最重要的部分。 但是對于特定于域的問題,如果有合適的匹配器,通常可以提高單元測試斷言的可讀性。

    因此,該庫允許編寫自定義匹配器。

    讓我們返回教程的示例來討論該主題。 首先,我們對該場景進(jìn)行調(diào)整以使其更合理。 假設(shè)NumberRangeCounter.next()返回的是RangeNumber類型,而不是簡單的int值:

    public class RangeNumber {private final String rangeIdentifier;private final int value;RangeNumber( String rangeIdentifier, int value ) {this.rangeIdentifier = rangeIdentifier;this.value = value;}public String getRangeIdentifier() {return rangeIdentifier;}public int getValue() {return value;} }

    我們可以使用自定義匹配器來檢查NumberRangeCounter#next()的返回值是否在計數(shù)器的定義數(shù)字范圍內(nèi):

    RangeNumber actual = counter.next();assertThat( actual, is( inRangeOf( LOWER_BOUND, RANGE ) ) );

    適當(dāng)?shù)淖远x匹配器可以擴(kuò)展抽象類TypeSafeMatcher<T> 。 該基類處理null檢查和類型安全。 可能的實現(xiàn)如下所示。 請注意如何添加工廠方法inRangeOf(int,int)以便于使用:

    public class InRangeMatcher extends TypeSafeMatcher<RangeNumber> {private final int lowerBound;private final int upperBound;InRangeMatcher( int lowerBound, int range ) {this.lowerBound = lowerBound;this.upperBound = lowerBound + range;}@Overridepublic void describeTo( Description description ) {String text = format( "between <%s> and <%s>.", lowerBound, upperBound );description.appendText( text );}@Overrideprotected void describeMismatchSafely(RangeNumber item, Description description ){description.appendText( "was " ).appendValue( item.getValue() );}@Overrideprotected boolean matchesSafely( RangeNumber toMatch ) {return lowerBound <= toMatch.getValue() && upperBound > toMatch.getValue();}public static Matcher<RangeNumber> inRangeOf( int lowerBound, int range ) {return new InRangeMatcher( lowerBound, range );} }

    對于給定的示例,工作量可能會有些夸大。 但它顯示了如何使用自定義匹配器消除先前帖子中有點神奇的IN_RANGE_NUMBER常量。 除了新類型外,還強制聲明語句的編譯時類型安全。 這意味著例如String參數(shù)將不被接受進(jìn)行驗證。

    下圖顯示了使用我們的自定義匹配器時測試結(jié)果失敗的樣子:

    很容易看出describeTo和describeMismatchSafely的實現(xiàn)以哪種方式影響故障消息。 它表示期望值應(yīng)該在指定的下限和(計算的)上限1之間 ,并跟在實際值之后。

    有點不幸的是,JUnit擴(kuò)展了其Assert類的API,以提供一組assertThat(…)方法。 這些方法實際上復(fù)制了MatcherAssert提供的API。 實際上,這些方法的實現(xiàn)委托給這種類型的相應(yīng)方法。

    盡管這可能只是個小問題,但我認(rèn)為值得一提。 由于這種方法,JUnit與Hamcrest庫牢固地聯(lián)系在一起。 這種依賴性有時會導(dǎo)致問題。 特別是與其他庫一起使用時,通過合并自己的hamcrest版本的副本,情況甚至更糟……

    Hamcrest的單元測試主張并非沒有競爭。 雖然關(guān)于每次測試一個確定與每個測試 一個概念的討論超出了本文的討論范圍,但后一種觀點的支持者可能認(rèn)為該庫的驗證聲明過于嘈雜。 尤其是當(dāng)一個概念需要多個斷言時。

    這就是為什么我必須在本章中添加另一部分!

    斷言

    在“ 測試跑步者”中,示例片段之一使用了兩個assertXXX語句。 這些驗證期望的異常是IllegalArgumentException的實例并提供特定的錯誤消息。 該段看起來像這樣:

    Throwable actual = ...assertTrue( actual instanceof IllegalArgumentException ); assertEquals( EXPECTED_ERROR_MESSAGE, actual.getMessage() );

    上一節(jié)教我們?nèi)绾问褂肏amcrest改進(jìn)代碼。 但是,如果您碰巧是該庫的新手,您可能會想知道要使用哪個表達(dá)式。 或打字可能會感到不舒服。 無論如何,多個assertThat語句會加在一起。

    AssertJ庫通過為Java提供流暢的斷言來努力改善這一點。 流暢的接口 API的目的是提供一種易于閱讀的,富有表現(xiàn)力的編程風(fēng)格,從而減少膠合代碼并簡化鍵入。

    那么如何使用這種方法來重構(gòu)上面的代碼?

    import static org.assertj.core.api.Assertions.assertThat;

    與其他方法類似,AssertJ提供了一個實用程序類,該類提供了一組靜態(tài)assertThat方法。 但是這些方法針對給定的參數(shù)類型返回特定的斷言實現(xiàn)。 這就是所謂的語句鏈接的起點。

    Throwable actual = ...assertThat( actual ).isInstanceOf( IllegalArgumentException.class ).hasMessage( EXPECTED_ERROR_MESSAGE );

    旁觀者認(rèn)為可讀性在某種程度上得到了擴(kuò)展,但無論如何都可以用更緊湊的樣式來寫斷言。 了解如何流暢地添加與被測特定概念相關(guān)的各種驗證方面。 這種編程方法支持有效的類型輸入,因為IDE的內(nèi)容輔助可以提供給定值類型的可用謂詞列表。

    因此,您想向后世提供表現(xiàn)力的失敗消息嗎? 一種可能是使用describedAs作為鏈中的第一個鏈接來注釋整個塊:

    Throwable actual = ...assertThat( actual ).describedAs( "Expected exception does not match specification." ).hasMessage( EXPECTED_ERROR_MESSAGE ).isInstanceOf( NullPointerException.class );

    該代碼段期望使用NPE,但假設(shè)在運行時拋出了IAE。 然后失敗的測試運行將提供如下消息:

    也許您希望根據(jù)給定的失敗原因使您的消息更加細(xì)微。 在這種情況下,您可以在每個驗證規(guī)范之前添加一條describedAs語句:

    Throwable actual = ...assertThat( actual ).describedAs( "Message does not match specification." ).hasMessage( EXPECTED_ERROR_MESSAGE ).describedAs( "Exception type does not match specification." ).isInstanceOf( NullPointerException.class );

    還有更多的AssertJ功能可供探索。 但是,要使該帖子保持在范圍內(nèi),請參閱實用程序的在線文檔以獲取更多信息。 但是,在結(jié)束之前,讓我們再次看一下范圍內(nèi)驗證示例。 這可以通過自定義斷言來解決:

    public class RangeCounterAssertionextends AbstractAssert<RangeCounterAssertion, RangeCounter> {private static final String ERR_IN_RANGE_OF = "Expected value to be between <%s> and <%s>, but was <%s>";private static final String ERR_RANGE_ID = "Expected range identifier to be <%s>, but was <%s>";public static RangeCounterAssertion assertThat( RangeCounter actual ) {return new RangeCounterAssertion( actual );}public InRangeAssertion hasRangeIdentifier( String expected ) {isNotNull();if( !actual.getRangeIdentifier().equals( expected ) ) {failWithMessage( ERR_RANGE_ID, expected, actual.getRangeIdentifier() );}return this;}public RangeCounterAssertion isInRangeOf( int lowerBound, int range ) {isNotNull();int upperBound = lowerBound + range;if( !isInInterval( lowerBound, upperBound ) ) {int actualValue = actual.getValue();failWithMessage( ERR_IN_RANGE_OF, lowerBound, upperBound, actualValue );}return this;}private boolean isInInterval( int lowerBound, int upperBound ) {return actual.getValue() >= lowerBound && actual.getValue() < upperBound;}private RangeCounterAssertion( Integer actual ) {super( actual, RangeCounterAssertion.class );} }

    自定義斷言是擴(kuò)展AbstractAssert常見做法。 第一個通用參數(shù)是斷言的類型本身。 流利的鏈接樣式需要它。 第二種是斷言所基于的類型。

    該實現(xiàn)提供了兩種附加的驗證方法,可以按照以下示例進(jìn)行鏈接。 因此,這些方法將返回斷言實例本身。 請注意, isNotNull()的調(diào)用如何確保我們要聲明的實際RangeNumber不為null 。

    定制斷言由其工廠方法assertThat(RangeNumber) 。 由于它繼承了可用的基本檢查,因此斷言可以開箱即用地驗證非常復(fù)雜的規(guī)范。

    RangeNumber first = ... RangeNumber second = ...assertThat( first ).isInRangeOf( LOWER_BOUND, RANGE ).hasRangeIdentifier( EXPECTED_RANGE_ID ).isNotSameAs( second );

    為了完整RangNumberAssertion ,以下是RangNumberAssertion的實際運行方式:

    不幸的是,不可能在同一測試用例中使用兩種不同的斷言類型和靜態(tài)導(dǎo)入。 當(dāng)然,假定這些類型遵循assertThat(...)命名約定。 為了避免這種情況,文檔建議擴(kuò)展實用程序類Assertions 。

    這樣的擴(kuò)展可用于提供靜態(tài)的assertThat方法,作為所有項目自定義斷言的入口。 通過在整個項目中使用此自定義實用程序類,不會發(fā)生導(dǎo)入沖突。 在為所有斷言提供單一入口點的部分中,可以找到詳細(xì)的描述:在線文檔中有關(guān)定制斷言的 yours + AssertJ 。

    流利的API的另一個問題是單行鏈接的語句可能更難調(diào)試。 這是因為調(diào)試器可能無法在鏈中設(shè)置斷點。 此外,可能不清楚哪個方法調(diào)用已引起異常。

    但是,正如Wikipedia所說的那樣,可以通過將語句分成多行來克服這些問題,如上面的示例所示。 這樣,用戶可以在鏈中設(shè)置斷點,輕松地逐行瀏覽代碼。

    結(jié)論

    簡而言之,JUnit的這一章介紹了不同的單元測試斷言方法,例如該工具的內(nèi)置機(jī)制,Hamcrest匹配器和AssertJ斷言。 它概述了一些優(yōu)缺點,并通過本教程的持續(xù)示例對主題進(jìn)行了擴(kuò)展。 此外,還展示了如何創(chuàng)建和使用自定義匹配器和斷言。

    盡管基于Assert的機(jī)制肯定是過時的且不太面向?qū)ο?#xff0c;但它仍然具有它的提倡者。 Hamcrest匹配器提供斷言和謂詞定義的清晰分隔,而AssertJ斷言以緊湊且易于使用的編程樣式進(jìn)行評分。 所以現(xiàn)在您選擇太多了……

    請注意,這將是本教程有關(guān)JUnit測試要點的最后一章。 這并不意味著沒有更多要說的了。 恰恰相反! 但這將超出此迷你系列量身定制的范圍。 而且您知道他們在說什么: 總是讓他們想要更多…

  • 嗯,我想知道區(qū)間邊界是否會比下限和范圍更直觀...
  • 翻譯自: https://www.javacodegeeks.com/2014/09/junit-in-a-nutshell-unit-test-assertion.html

    junit單元測試斷言

    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

    總結(jié)

    以上是生活随笔為你收集整理的junit单元测试断言_简而言之,JUnit:单元测试断言的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。