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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

扩展 junit 框架_JUnit 5 –扩展模型

發(fā)布時(shí)間:2023/12/3 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 扩展 junit 框架_JUnit 5 –扩展模型 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

擴(kuò)展 junit 框架

我們已經(jīng)對Java最普遍的測試框架的下一個(gè)版本了解很多。 現(xiàn)在,讓我們看一下JUnit 5擴(kuò)展模型,該模型將允許庫和框架將自己的實(shí)現(xiàn)添加到JUnit中。

總覽

  • 建立
  • 基本
  • 建筑
  • 擴(kuò)展模型
  • 條件
  • 注射

在新興的《 JUnit 5用戶指南》中可以找到您將在此處閱讀的更多內(nèi)容以及更多內(nèi)容。 請注意,它基于Alpha版本,因此可能會發(fā)生變化。

確實(shí),我們鼓勵(lì)我們提出問題或提出請求,以便JUnit 5可以進(jìn)一步改進(jìn)。 請利用這個(gè)機(jī)會! 這是我們幫助JUnit幫助我們的機(jī)會,因此,如果您能在這里看到一些改善,請確保將其上游 。

如有必要,此帖子將得到更新。 我在這里顯示的代碼示例可以在GitHub上找到 。

JUnit 4擴(kuò)展模型

首先讓我們看一下JUnit 4是如何解決該問題的。 它具有兩個(gè)部分競爭的擴(kuò)展機(jī)制:運(yùn)行程序和規(guī)則。

跑步者

測試運(yùn)行者管理測試的生命周期:實(shí)例化,調(diào)用設(shè)置和拆卸方法,運(yùn)行測試,處理異常,發(fā)送通知等。JUnit4提供了實(shí)現(xiàn)所有這些功能的實(shí)現(xiàn)。

在4.0中,只有一種擴(kuò)展JUnit的方法:創(chuàng)建一個(gè)新的運(yùn)行器并使用@RunWith(MyRunner.class)注釋測試類,以便JUnit使用它而不是其自己的實(shí)現(xiàn)。

該機(jī)制非常繁重,并且擴(kuò)展范圍很小。 而且它有一個(gè)非常嚴(yán)格的限制:每個(gè)測試班級只能有一個(gè)跑步者,這使得他們無法組成。 因此,無法同時(shí)利用Mockito和Spring跑步者的功能。

規(guī)則

為了克服這些限制,JUnit 4.7引入了rules ,它們是測試類的帶注釋字段。 JUnit 4將測試方法(和其他操作)包裝到一條語句中,并將其傳遞給規(guī)則。 然后,他們可以在執(zhí)行語句之前和之后執(zhí)行一些代碼。 此外,測試方法通常在執(zhí)行期間在規(guī)則實(shí)例上調(diào)用方法。

一個(gè)示例是臨時(shí)文件夾規(guī)則 :

public static class HasTempFolder {@Rulepublic TemporaryFolder folder= new TemporaryFolder();@Testpublic void testUsingTempFolder() throws IOException {File createdFile= folder.newFile("myfile.txt");File createdFolder= folder.newFolder("subfolder");// ...} }

由于使用@Rule批注,JUnit調(diào)用帶有包裝方法testUsingTempFolder的語句的文件夾 。 編寫此特定規(guī)則是為了使文件夾創(chuàng)建一個(gè)臨時(shí)文件夾,執(zhí)行測試,然后再刪除該文件夾。 然后,測試本身可以在臨時(shí)文件夾中創(chuàng)建文件和文件夾。

其他規(guī)則可能會在Swing的事件分發(fā)線程中運(yùn)行測試 ,建立和拆除數(shù)據(jù)庫,或者如果測試運(yùn)行時(shí)間過長,則讓測試超時(shí) 。

規(guī)則是一個(gè)很大的改進(jìn),但是通常僅限于在測試運(yùn)行之前和之后執(zhí)行一些代碼。 他們無法幫助無法在該框架內(nèi)實(shí)現(xiàn)的擴(kuò)展。

事態(tài)

JUnit有兩種相互競爭的擴(kuò)展機(jī)制,每種都有其自身的局限性。

因此,自JUnit 4.7起,就有兩種競爭的擴(kuò)展機(jī)制,每種都有其自身的局限性,但也有很多重疊之處。 這使得干凈擴(kuò)展很困難。 此外,編寫不同的擴(kuò)展可能會出現(xiàn)問題,并且通常無法實(shí)現(xiàn)開發(fā)人員希望的擴(kuò)展。

由Tony Walmsley在CC-BY 2.0下發(fā)布

JUnit 5擴(kuò)展模型

JUnit Lambda項(xiàng)目具有兩個(gè)核心原則 ,其中之一是“優(yōu)先于功能而不是擴(kuò)展點(diǎn)”。 從字面上看,這轉(zhuǎn)化為新版本的整體機(jī)制–這不僅是擴(kuò)展JUnit 5的唯一機(jī)制,也是最重要的機(jī)制。

延伸點(diǎn)

JUnit 5擴(kuò)展可以聲明對測試生命周期的某些特定時(shí)刻感興趣。 當(dāng)JUnit 5引擎處理測試時(shí),它將逐步通過這些步驟并調(diào)用每個(gè)已注冊的擴(kuò)展。 從外觀上看,這些是擴(kuò)展點(diǎn):

  • 測試實(shí)例后處理
  • 之前回調(diào)
  • 有條件的測試執(zhí)行
  • 每次回調(diào)之前
  • 參數(shù)解析
  • 異常處理
  • AfterEach回調(diào)
  • 畢竟回調(diào)

(不要擔(dān)心它們是否每個(gè)都不清楚。我們稍后會介紹其中的一些。)

每個(gè)擴(kuò)展點(diǎn)對應(yīng)一個(gè)接口。 他們的方法采用的參數(shù)可以捕獲測試生命周期中特定點(diǎn)的上下文,例如測試實(shí)例和方法,測試名稱,參數(shù),注釋等。

擴(kuò)展可以實(shí)現(xiàn)任何數(shù)量的那些接口,并且將由引擎使用相應(yīng)的參數(shù)進(jìn)行調(diào)用。 然后,它可以執(zhí)行實(shí)現(xiàn)其功能所需的任何操作。 需要考慮的一個(gè)細(xì)節(jié):引擎在實(shí)例化擴(kuò)展時(shí)以及將實(shí)例保留多長時(shí)間時(shí)不做任何保證,因此它們必須是無狀態(tài)的。 他們需要維護(hù)的任何狀態(tài)都必須寫入JUnit并從中加載。

創(chuàng)建擴(kuò)展后,剩下要做的就是告訴JUnit。 這是那么容易,因?yàn)樘砑?span id="crayon-570cd6cb160ed677604253" class="crayon-syntax crayon-syntax-inline crayon-theme-eclipse-nipa crayon-theme-eclipse-nipa-inline crayon-font-liberation-mono">@ExtendWith(MyExtension。 ),需要延長測試類或方法。

實(shí)際上,存在一個(gè)稍微不那么冗長和更多顯示的選項(xiàng)。 但是為此,我們首先必須看看JUnit擴(kuò)展模型的另一個(gè)Struts。

自定義注釋

JUnit 5 API由注釋驅(qū)動(dòng),當(dāng)引擎檢查它們的存在時(shí),它會做一些額外的工作:它不僅在類,方法和參數(shù)上查找注釋,還在其他注釋上查找。 并且它將發(fā)現(xiàn)的所有內(nèi)容都視為立即存在于所檢查的元素上。 注釋可以通過所謂的meta-annotations進(jìn)行注釋 ,很酷的是,所有JUnit注釋都是完全meta的。

這樣就可以輕松創(chuàng)建和編寫在JUnit 5中完全可用的注釋:

/*** We define a custom annotation that:* - stands in for '@Test' so that the method gets executed* - has the tag "integration" so we can filter by that,* e.g. when running tests from the command line*/ @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Test @Tag("integration") public @interface IntegrationTest { }

然后我們可以像這樣使用它:

@IntegrationTest void runsWithCustomAnnotation() {// this gets executed// even though `@IntegrationTest` is not defined by JUnit }

或者我們可以為擴(kuò)展創(chuàng)建更簡潔的注釋:

@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.ANNOTATION_TYPE }) @Retention(RetentionPolicy.RUNTIME) @ExtendWith(ExternalDatabaseExtension.class) public @interface Database { }

現(xiàn)在我們可以使用@Database代替@ExtendWith(ExternalDatabaseExtension。 )。 由于我們添加了ElementType ANNOTATION_TYPE到允許的目標(biāo)列表中,它也是一個(gè)元注釋,我們或其他人可以對其進(jìn)行進(jìn)一步的組合。

假設(shè)我們要對某些測試的運(yùn)行時(shí)間進(jìn)行基準(zhǔn)測試。 首先,我們創(chuàng)建要使用的注釋:

@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.ANNOTATION_TYPE }) @Retention(RetentionPolicy.RUNTIME) @ExtendWith(BenchmarkCondition.class) public @interface Benchmark { }

它已經(jīng)指向BenchmarkCondition ,我們將在接下來實(shí)現(xiàn)。 這是我們的計(jì)劃:

  • 衡量整個(gè)測試類的運(yùn)行時(shí)間,存儲執(zhí)行任何測試之前的時(shí)間
  • 衡量各個(gè)測試方法的運(yùn)行時(shí)間,存儲每次測試之前的時(shí)間
  • 執(zhí)行測試方法后,檢索測試的啟動(dòng)時(shí)間,計(jì)算并打印結(jié)果運(yùn)行時(shí)
  • 執(zhí)行完所有測試后,檢索類的啟動(dòng)時(shí)間,計(jì)算并打印結(jié)果運(yùn)行時(shí)
  • 僅當(dāng)使用@Benchmark注釋類或方法時(shí),才執(zhí)行任何此操作

最后一點(diǎn)可能不會立即顯而易見。 為什么擴(kuò)展名不會處理未用@Benchmark注釋的方法? 這源于以下事實(shí):如果將擴(kuò)展應(yīng)用于類,它將自動(dòng)應(yīng)用于其中的所有方法。 因此,如果我們的要求表明我們可能希望對類進(jìn)行基準(zhǔn)測試,但不一定要對所有單個(gè)方法進(jìn)行基準(zhǔn)測試,則需要排除它們。 我們通過檢查它們是否被單獨(dú)注釋來做到這一點(diǎn)。

碰巧的是,前四個(gè)點(diǎn)直接對應(yīng)于生命周期回調(diào)BeforeAll , BeforeEach , AfterEach , AfterAll ,因此我們要做的就是實(shí)現(xiàn)四個(gè)對應(yīng)的接口。 這些實(shí)現(xiàn)非常簡單,它們只是按照我們上面所說的去做:

public class BenchmarkCondition implementsBeforeAllExtensionPoint, BeforeEachExtensionPoint,AfterEachExtensionPoint, AfterAllExtensionPoint {private static final Namespace NAMESPACE =Namespace.of("BenchmarkCondition");@Overridepublic void beforeAll(ContainerExtensionContext context) {if (!shouldBeBenchmarked(context))return;writeCurrentTime(context, LaunchTimeKey.CLASS);}@Overridepublic void beforeEach(TestExtensionContext context) {if (!shouldBeBenchmarked(context))return;writeCurrentTime(context, LaunchTimeKey.TEST);}@Overridepublic void afterEach(TestExtensionContext context) {if (!shouldBeBenchmarked(context))return;long launchTime = loadLaunchTime(context, LaunchTimeKey.TEST);long runtime = currentTimeMillis() - launchTime;print("Test", context.getDisplayName(), runtime);}@Overridepublic void afterAll(ContainerExtensionContext context) {if (!shouldBeBenchmarked(context))return;long launchTime = loadLaunchTime(context, LaunchTimeKey.CLASS);long runtime = currentTimeMillis() - launchTime;print("Test container", context.getDisplayName(), runtime);}private static boolean shouldBeBenchmarked(ExtensionContext context) {return context.getElement().isAnnotationPresent(Benchmark.class);}private static void writeCurrentTime(ExtensionContext context, LaunchTimeKey key) {context.getStore(NAMESPACE).put(key, currentTimeMillis());}private static long loadLaunchTime(ExtensionContext context, LaunchTimeKey key) {return (Long) context.getStore(NAMESPACE).remove(key);}private static void print(String unit, String displayName, long runtime) {System.out.printf("%s '%s' took %d ms.%n", unit, displayName, runtime);}private enum LaunchTimeKey {CLASS, TEST} }

有趣的細(xì)節(jié)是shouldBeBenchmarked ,它使用JUnit的API毫不費(fèi)力地確定當(dāng)前元素是否被@Benchmark (元)注釋,以及writeCurrentTime / loadLaunchTime ,后者使用存儲來寫入和讀取啟動(dòng)時(shí)間。

  • 您可以在GitHub上找到代碼 。

下一篇文章將討論條件測試執(zhí)行和參數(shù)注入,并顯示有關(guān)如何使用相應(yīng)擴(kuò)展點(diǎn)的示例。 如果您迫不及待,請查看這篇文章 ,其中展示了如何將兩個(gè)JUnit 4規(guī)則(條件禁用和臨時(shí)文件夾)移植到JUnit 5。

摘要

我們已經(jīng)看到,JUnit 4的運(yùn)行者和規(guī)則對于創(chuàng)建干凈,強(qiáng)大且可組合的擴(kuò)展不是理想的選擇。 JUnit 5旨在通過更通用的擴(kuò)展點(diǎn)概念來克服它們的局限性。 它們允許擴(kuò)展程序指定要在測試生命周期中的哪些時(shí)間點(diǎn)進(jìn)行干預(yù)。 我們還研究了元注釋如何使輕松創(chuàng)建自定義注釋成為可能。

你怎么看?

翻譯自: https://www.javacodegeeks.com/2016/04/junit-5-extension-model.html

擴(kuò)展 junit 框架

總結(jié)

以上是生活随笔為你收集整理的扩展 junit 框架_JUnit 5 –扩展模型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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