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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

五年了,你还在用junit4吗?

發(fā)布時(shí)間:2025/3/16 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 五年了,你还在用junit4吗? 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

junit5

JUnit5在2017年就發(fā)布了,你還在用junit4嗎?

什么是junit5

與以前的JUnit版本不同,JUnit 5由三個(gè)不同子項(xiàng)目的多個(gè)不同模塊組成。

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

JUnit Platform為在JVM上啟動(dòng)測(cè)試框架提供基礎(chǔ)。它還定義了TestEngine API, 用來開發(fā)在平臺(tái)上運(yùn)行的測(cè)試框架。此外,平臺(tái)提供了一個(gè)控制臺(tái)啟動(dòng)器],用于從命令行啟動(dòng)平臺(tái),并為Gradle和Maven提供構(gòu)建插件以[基于JUnit 4的Runner,用于在平臺(tái)上運(yùn)行任意TestEngine。

JUnit Jupiter是在JUnit 5中編寫測(cè)試和擴(kuò)展的新型編程模型和[擴(kuò)展模型][]的組合.Jupiter子項(xiàng)目提供了TestEngine,用于在平臺(tái)上運(yùn)行基于Jupiter的測(cè)試。

JUnit Vintage提供TestEngine,用于在平臺(tái)上運(yùn)行基于JUnit 3和JUnit 4的測(cè)試。

為什么需要 JUnit 5

自從有了類似 JUnit 之類的測(cè)試框架,Java 單元測(cè)試領(lǐng)域逐漸成熟,開發(fā)人員對(duì)單元測(cè)試框架也有了更高的要求:更多的測(cè)試方式,更少的其他庫(kù)的依賴。

因此,大家期待著一個(gè)更強(qiáng)大的測(cè)試框架誕生,JUnit 作為Java測(cè)試領(lǐng)域的領(lǐng)頭羊,推出了 JUnit 5 這個(gè)版本,主要特性:

  • 提供全新的斷言和測(cè)試注解,支持測(cè)試類內(nèi)嵌

  • 更豐富的測(cè)試方式:支持動(dòng)態(tài)測(cè)試,重復(fù)測(cè)試,參數(shù)化測(cè)試等

  • 實(shí)現(xiàn)了模塊化,讓測(cè)試執(zhí)行和測(cè)試發(fā)現(xiàn)等不同模塊解耦,減少依賴

  • 提供對(duì) Java 8 的支持,如 Lambda 表達(dá)式,Sream API等。

基本注解

@Test:?表示方法是測(cè)試方法。但是與JUnit4的@Test不同,他的職責(zé)非常單一不能聲明任何屬性,拓展的測(cè)試將會(huì)由Jupiter提供額外測(cè)試

@ParameterizedTest: 表示方法是參數(shù)化測(cè)試

@RepeatedTest: 表示方法可重復(fù)執(zhí)行

@DisplayName: 為測(cè)試類或者測(cè)試方法設(shè)置展示名稱

@BeforeEach: 表示在每個(gè)單元測(cè)試之前執(zhí)行

@AfterEach: 表示在每個(gè)單元測(cè)試之后執(zhí)行

@BeforeAll: 表示在所有單元測(cè)試之前執(zhí)行

@AfterAll: 表示在所有單元測(cè)試之后執(zhí)行

@Tag: 表示單元測(cè)試類別,類似于JUnit4中的@Categories

@Disabled: 表示測(cè)試類或測(cè)試方法不執(zhí)行,類似于JUnit4中的@Ignore

@Timeout: 表示測(cè)試方法運(yùn)行如果超過了指定時(shí)間將會(huì)返回錯(cuò)誤

@ExtendWith: 為測(cè)試類或測(cè)試方法提供擴(kuò)展類引用

常用注解格式:

class?StandardTests?{//與junit4的@beforeClass類似,每個(gè)測(cè)試類運(yùn)行一次@BeforeAllstatic?void?initAll()?{}//與junit4中@before類似,每個(gè)測(cè)試用例都運(yùn)行一次@BeforeEachvoid?init()?{}@Test@DisplayName("成功測(cè)試")void?succeedingTest()?{}@Test@DisplayName("失敗測(cè)試")void?failingTest()?{fail("a?failing?test");}//禁用測(cè)試用例@Test@Disabled("for?demonstration?purposes")void?skippedTest()?{//?not?executed}@Testvoid?abortedTest()?{assumeTrue("abc".contains("Z"));fail("test?should?have?been?aborted");}//與@BeforeEach對(duì)應(yīng),每個(gè)測(cè)試類執(zhí)行一次,一般用于恢復(fù)環(huán)境@AfterEachvoid?tearDown()?{}//與@BeforeAll對(duì)應(yīng),每個(gè)測(cè)試類執(zhí)行一次,一般用于恢復(fù)環(huán)境@AfterAllstatic?void?tearDownAll()?{} }

?

新特性

顯示名稱

@DisplayName("顯示名稱測(cè)試") class?DisplayNameDemo?{@Test@DisplayName("我的?第一個(gè)?測(cè)試?用例")void?testWithDisplayNameContainingSpaces()?{}@Test@DisplayName("╯°□°)╯")void?testWithDisplayNameContainingSpecialCharacters()?{}@Test@DisplayName("????")void?testWithDisplayNameContainingEmoji()?{} }

IDE運(yùn)行測(cè)試結(jié)果顯示:

image-20210416232329161

**優(yōu)點(diǎn):**通過這種方式,可以在方法名是英文特別長(zhǎng)或者很難用英文描述清楚的場(chǎng)景下,增加中文解釋

更強(qiáng)大的斷言

JUnit Jupiter提供了許多JUnit4已有的斷言方法,并增加了一些適合與Java 8 lambda一起使用的斷言方法。所有JUnit Jupiter斷言都是[org.junit.jupiter.Assertions]類中的靜態(tài)方法。

分組斷言:

多個(gè)條件同時(shí)滿足時(shí)才斷言成功

@Test void?groupedAssertions()?{Person?person?=?new?Person();Assertions.assertAll("person",()?->?assertEquals("niu",?person.getName()),()?->?assertEquals(18,?person.getAge())); }

異常斷言:

Junit4時(shí)需要使用rule方式,junit5提供了assertThrows更優(yōu)雅的異常斷言

@Test void?exceptionTesting()?{Throwable?exception?=?assertThrows(IllegalArgumentException.class,?()?->?{throw?new?IllegalArgumentException("a?message");});assertEquals("a?message",?exception.getMessage()); }

超時(shí)斷言:

@Test @DisplayName("超時(shí)測(cè)試") public?void?timeoutTest()?{Assertions.assertTimeout(Duration.ofMillis(100),?()?->?Thread.sleep(50)); }

標(biāo)簽和過濾

通過標(biāo)簽把測(cè)試分組,在不同階段執(zhí)行不同的邏輯測(cè)試,比如劃分為快速冒煙測(cè)試和執(zhí)行慢但也重要的測(cè)試

@Test @Tag("fast")void?testing_faster()?{ }@Test @Tag("slow")void?testing_slow()?{ }

然后通過配置maven-surefire-plugin插件

<plugin><artifactId>maven-surefire-plugin</artifactId><version>2.22.0</version><configuration><properties><includeTags>fast</includeTags><excludeTages>slow</excludeTages></properties></configuration> </plugin>

嵌套測(cè)試

當(dāng)我們編寫的類和代碼逐漸增多,隨之而來的需要測(cè)試的對(duì)應(yīng)測(cè)試類也會(huì)越來越多。

為了解決測(cè)試類數(shù)量爆炸的問題,JUnit 5提供了@Nested 注解,能夠以靜態(tài)內(nèi)部成員類的形式對(duì)測(cè)試用例類進(jìn)行邏輯分組。

并且每個(gè)靜態(tài)內(nèi)部類都可以有自己的生命周期方法, 這些方法將按從外到內(nèi)層次順序執(zhí)行。

此外,嵌套的類也可以用@DisplayName 標(biāo)記,這樣我們就可以使用正確的測(cè)試名稱。下面看下簡(jiǎn)單的用法:

@DisplayName("A?stack") class?TestingAStackDemo?{Stack<Object>?stack;@Test@DisplayName("is?instantiated?with?new?Stack()")void?isInstantiatedWithNew()?{new?Stack<>();}@Nested@DisplayName("when?new")class?WhenNew?{@BeforeEachvoid?createNewStack()?{stack?=?new?Stack<>();}@Test@DisplayName("is?empty")void?isEmpty()?{assertTrue(stack.isEmpty());}@Nested@DisplayName("after?pushing?an?element")class?AfterPushing?{String?anElement?=?"an?element";@BeforeEachvoid?pushAnElement()?{stack.push(anElement);}@Test@DisplayName("it?is?no?longer?empty")void?isNotEmpty()?{assertFalse(stack.isEmpty());}}} }

junit沒有限制嵌套層數(shù),除非必要一般不建議使用超過3層,過于復(fù)雜的層次結(jié)構(gòu)會(huì)增加開發(fā)者理解用例關(guān)系的難度

構(gòu)造函數(shù)和方法的依賴注入

在之前的所有JUnit版本中,測(cè)試構(gòu)造函數(shù)或方法都不允許有參數(shù)(至少不能使用標(biāo)準(zhǔn)的Runner實(shí)現(xiàn))。作為JUnit Jupiter的主要變化之一,測(cè)試構(gòu)造函數(shù)和方法現(xiàn)在都允許有參數(shù)。這帶來了更大的靈活性,并為構(gòu)造函數(shù)和方法啟用依賴注入

  • TestInfo可獲取測(cè)試信息

  • TestReporter可以向控制臺(tái)輸出信息

@Test @DisplayName("test-first") @Tag("my-tag") void?test1(TestInfo?testInfo)?{assertEquals("test-first",?testInfo.getDisplayName());assertTrue(testInfo.getTags().contains("my-tag")); }@Test @DisplayName("test-second") @Tag("my-tag") void?test2(TestReporter?testReporter)?{testReporter.publishEntry("a?key",?"a?value"); }

重復(fù)測(cè)試

多次調(diào)用同一個(gè)測(cè)試用例

@RepeatedTest(10) @DisplayName("重復(fù)測(cè)試") public?void?testRepeated()?{//... } image-20210416232512919

動(dòng)態(tài)測(cè)試

動(dòng)態(tài)測(cè)試只需要編寫一處代碼,就能一次性對(duì)各種類型的輸入和輸出結(jié)果進(jìn)行驗(yàn)證

@TestFactory @DisplayName("動(dòng)態(tài)測(cè)試") Stream<DynamicTest>?dynamicTests()?{List<Person>?persons?=?getAllPerson();return?persons.stream().map(person?->?DynamicTest.dynamicTest(person.getName()?+?"-test",?()?->?assertTrue(person.getName().contains("niu")))); }

超時(shí)測(cè)試

通過時(shí)間來驗(yàn)證用例是否超時(shí),一般要求單個(gè)單元測(cè)試不應(yīng)該超過1秒

class?TimeoutDemo?{@BeforeEach@Timeout(5)void?setUp()?{//?fails?if?execution?time?exceeds?5?seconds}@Test@Timeout(value?=?1000,?unit?=?TimeUnit.MILLISECONDS)void?failsIfExecutionTimeExceeds1000Milliseconds()?{//?fails?if?execution?time?exceeds?1000?milliseconds//也可用這種方式?Assertions.assertTimeout(Duration.ofMillis(1000),?()?->?Thread.sleep(1500));} }

參數(shù)測(cè)試

參數(shù)測(cè)試我覺得是最好用的特性,可以大量減少重復(fù)模板式代碼,也是junit5最驚艷的提升,強(qiáng)烈推薦使用

@ValueSource: 為參數(shù)化測(cè)試指定入?yún)碓?#xff0c;支持八大基礎(chǔ)類以及String類型,Class類型

@NullSource: 表示為參數(shù)化測(cè)試提供一個(gè)null的入?yún)?/p>

@EnumSource: 表示為參數(shù)化測(cè)試提供一個(gè)枚舉入?yún)?/p>

@CsvSource:表示讀取CSV格式內(nèi)容作為參數(shù)化測(cè)試入?yún)?/p>

@CsvFileSource:表示讀取指定CSV文件內(nèi)容作為參數(shù)化測(cè)試入?yún)?/p>

@MethodSource:表示讀取指定方法的返回值作為參數(shù)化測(cè)試入?yún)?注意方法返回需要是一個(gè)流)

@ArgumentsSource:指定一個(gè)自定義的,可重用的ArgumentsProvider。

看完用法描述,簡(jiǎn)直太喜歡了

一個(gè)頂三個(gè)基礎(chǔ)測(cè)試用例

@ParameterizedTest @ValueSource(strings?=?{"one",?"two",?"three"}) @DisplayName("參數(shù)化測(cè)試1") public?void?parameterizedTest1(String?string)?{assertTrue(StringUtils.isNotBlank(string)); } image-20210416233807174

如果不是基礎(chǔ)的類型,可以使用方法構(gòu)造,只要返回值為Stream類型就可以,多個(gè)參數(shù)使用Arguments實(shí)例流

@ParameterizedTest @MethodSource("method") @DisplayName("方法來源參數(shù)") public?void?testWithExplicitLocalMethodSource(String?name)?{Assertions.assertNotNull(name); }private?static?Stream<String>?method()?{return?Stream.of("apple",?"banana"); }

@CsvSource允許您將參數(shù)列表表示為以逗號(hào)分隔的值(例如,字符串文字)

@ParameterizedTest @CsvSource({"steven,18",?"jack,24"}) @DisplayName("參數(shù)化測(cè)試-csv格式") public?void?parameterizedTest3(String?name,?Integer?age)?{System.out.println("name:"?+?name?+?",age:"?+?age);Assertions.assertNotNull(name);Assertions.assertTrue(age?>?0); } image-20210416232702304

@CsvFileSource使用classpath中的CSV文件,CSV文件中的每一行都會(huì)導(dǎo)致參數(shù)化測(cè)試的一次調(diào)用

這種就完全把測(cè)試數(shù)據(jù)與測(cè)試方法隔離,達(dá)到更好解耦效果

@ParameterizedTest @CsvFileSource(resources?=?"/persons.csv")??//指定csv文件位置 @DisplayName("參數(shù)化測(cè)試-csv文件") public?void?parameterizedTest2(String?name,?Integer?age)?{System.out.println("name:"?+?name?+?",age:"?+?age);Assertions.assertNotNull(name);Assertions.assertTrue(age?>?0); }

其他方式不在贅述,如果還是滿足不了需求,可以通過@ArgumentsSource自定義自己的數(shù)據(jù)來源,必須封裝成去取JSON或者XMl等數(shù)據(jù)

AssertJ

當(dāng)定義好需要運(yùn)行的測(cè)試方法后,下一步則是需要關(guān)注測(cè)試方法的細(xì)節(jié),這就離不開斷言和假設(shè)

斷言:封裝好了常用判斷邏輯,當(dāng)不滿足條件時(shí),該測(cè)試用例會(huì)被認(rèn)為測(cè)試失敗

假設(shè):與斷言類似,當(dāng)條件不滿足時(shí),測(cè)試會(huì)直接退出而不是判定為失敗

因?yàn)椴粫?huì)影響到后續(xù)的測(cè)試用例,最常用的還是斷言

除了Junit5自帶的斷言,AssertJ是非常好用的一個(gè)斷言工具,最大特點(diǎn)是提供了流式斷言,與Java8使用方法非常類似

@Test void?testString()?{//?斷言null或?yàn)榭兆址產(chǎn)ssertThat("").isNullOrEmpty();//?斷言空字符串a(chǎn)ssertThat("").isEmpty();//?斷言字符串相等?斷言忽略大小寫判斷字符串相等assertThat("niu").isEqualTo("niu").isEqualToIgnoringCase("NIu");//?斷言開始字符串?結(jié)束字符穿?字符串長(zhǎng)度assertThat("niu").startsWith("ni").endsWith("u").hasSize(3);//?斷言包含字符串?不包含字符串a(chǎn)ssertThat("niu").contains("iu").doesNotContain("love");//?斷言字符串只出現(xiàn)過一次assertThat("niu").containsOnlyOnce("iu"); }@Test void?testNumber()?{//?斷言相等assertThat(42).isEqualTo(42);//?斷言大于?大于等于assertThat(42).isGreaterThan(38).isGreaterThanOrEqualTo(38);//?斷言小于?小于等于assertThat(42).isLessThan(58).isLessThanOrEqualTo(58);//?斷言0assertThat(0).isZero();//?斷言正數(shù)?非負(fù)數(shù)assertThat(1).isPositive().isNotNegative();//?斷言負(fù)數(shù)?非正數(shù)assertThat(-1).isNegative().isNotPositive(); }@Test void?testCollection()?{//?斷言?列表是空的assertThat(newArrayList()).isEmpty();//?斷言?列表的開始?結(jié)束元素assertThat(newArrayList(1,?2,?3)).startsWith(1).endsWith(3);//?斷言?列表包含元素?并且是排序的assertThat(newArrayList(1,?2,?3)).contains(1,?atIndex(0)).contains(2,?atIndex(1)).contains(3).isSorted();//?斷言?被包含與給定列表assertThat(newArrayList(3,?1,?2)).isSubsetOf(newArrayList(1,?2,?3,?4));//?斷言?存在唯一元素assertThat(newArrayList("a",?"b",?"c")).containsOnlyOnce("a"); }@Test void?testMap()?{Map<String,?Object>?foo?=?ImmutableMap.of("A",?1,?"B",?2,?"C",?3);//?斷言?map?不為空?sizeassertThat(foo).isNotEmpty().hasSize(3);//?斷言?map?包含元素assertThat(foo).contains(entry("A",?1),?entry("B",?2));//?斷言?map?包含keyassertThat(foo).containsKeys("A",?"B",?"C");//?斷言?map?包含valueassertThat(foo).containsValue(3); } //?其他斷言,請(qǐng)自行探索......

想想如果沒有使用AssertJ時(shí)我們是如何寫斷言的,是不是需要多個(gè)assert,很繁瑣

AssertJ的斷言代碼清爽很多,流式斷言充分利用了java8之后的匿名方法和stream類型的特點(diǎn),很好的對(duì)Junit斷言方法做了補(bǔ)充。

參考

https://junit.org/junit5/docs/current/user-guide/#overview

https://assertj.github.io/doc/

有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)

歡迎大家關(guān)注Java之道公眾號(hào)

好文章,我在看??

總結(jié)

以上是生活随笔為你收集整理的五年了,你还在用junit4吗?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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