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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

junit5和junit4_JUnit 5 –条件

發布時間:2023/12/3 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 junit5和junit4_JUnit 5 –条件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

junit5和junit4

最近,我們了解了JUnit的新擴展模型以及它如何使我們能夠將自定義行為注入測試引擎。 我向你保證要看情況。 現在就開始吧!

條件允許我們在應該執行或不應該執行測試時定義靈活的標準。 它們的正式名稱是“ 條件測試執行” 。

總覽

本系列中有關JUnit 5的其他文章:

  • 建立
  • 基本
  • 建筑
  • 擴展模型
  • 條件
  • 注射

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

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

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

條件擴展點

還記得我們所說的擴展點嗎? 沒有? 簡而言之:它們很多,每個都與特定的接口有關。 可以將這些接口的實現傳遞給JUnit(帶有@ExtendWith批注),它將在適當的時候調用它們。

對于條件,需要關注兩個擴展點:ContainerExecutionCondition和TestExecutionCondition。

public interface ContainerExecutionCondition extends Extension {/*** Evaluate this condition for the supplied ContainerExtensionContext.** An enabled result indicates that the container should be executed;* whereas, a disabled result indicates that the container should not* be executed.** @param context the current ContainerExtensionContext*/ConditionEvaluationResult evaluate(ContainerExtensionContext context);}public interface TestExecutionCondition extends Extension {/*** Evaluate this condition for the supplied TestExtensionContext.** An enabled result indicates that the test should be executed;* whereas, a disabled result indicates that the test should not* be executed.** @param context the current TestExtensionContext*/ConditionEvaluationResult evaluate(TestExtensionContext context);}

ContainerExecutionCondition確定是否執行容器中的測試。 在帶有注釋測試方法的通常情況下,測試類將是容器。 在同一場景中,各個測試方法的執行由TestExecutionConditions確定。

(我說“在通常情況下”是因為不同的測試引擎對容器和測試的解釋可能非常不同。類和方法只是最常見的解釋。)

這已經差不多了。 任何條件都應實現這些接口中的一個或兩個,并在其評估實現中進行所需的檢查。

@已停用

最簡單的條件是甚至沒有評估的條件:如果存在我們手工制作的注釋,我們總是總是禁用測試。

因此,讓我們創建@Disabled:

@Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @ExtendWith(@DisabledCondition.class) public @interface Disabled { }

和匹配的擴展名:

public class DisabledConditionimplements ContainerExecutionCondition, TestExecutionCondition {private static final ConditionEvaluationResult ENABLED =ConditionEvaluationResult.enabled("@Disabled is not present");@Overridepublic ConditionEvaluationResult evaluate(ContainerExtensionContext context) {return evaluateIfAnnotated(context.getElement());}@Overridepublic ConditionEvaluationResult evaluate(TestExtensionContext context) {return evaluateIfAnnotated(context.getElement());}private ConditionEvaluationResult evaluateIfAnnotated(AnnotatedElement element) {Optional<Disabled> disabled = AnnotationUtils.findAnnotation(element, Disabled.class);if (disabled.isPresent())return ConditionEvaluationResult.disabled(element + " is @Disabled");return ENABLED;}}

像餡餅一樣容易,對吧? 也是正確的,因為它與真正的@Disabled實現幾乎相同。 只有兩個小區別:

  • 官方注釋不需要隨身攜帶擴展名,因為它是默認注冊的。
  • 可以給出一個原因,當跳過禁用的測試時會記錄該原因。

小警告(當然,您有什么想法?):AnnotationUtils是內部API,但其功能可能很快就會正式可用 。

現在,讓我們嘗試一些不那么瑣碎的事情。

@DisabledOnOs

如果我們使用的是正確的操作系統,也許我們只想運行一些測試。

簡單的解決方案

同樣,我們從注釋開始:

@Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @ExtendWith(OsCondition.class) public @interface DisabledOnOs {OS[] value() default {};}

這次需要一個值,如果不是,則取一堆,即不應運行測試的操作系統。 OS只是一個枚舉,每個操作系統都有一個值。 而且它有一個方便的靜態OS define()方法,您猜對了,它確定了代碼在其上運行的操作系統。

這樣,讓我們??轉向OsCondition。 它必須檢查注釋是否存在,但還要檢查當前的操作系統是否是提供給注釋的操作系統之一。

public class OsCondition implements ContainerExecutionCondition, TestExecutionCondition {// both `evaluate` methods forward to `evaluateIfAnnotated` as aboveprivate ConditionEvaluationResult evaluateIfAnnotated(AnnotatedElement element) {Optional<DisabledOnOs> disabled = AnnotationUtils.findAnnotation(element, DisabledOnOs.class);if (disabled.isPresent())return disabledIfOn(disabled.get().value());return ENABLED;}private ConditionEvaluationResult disabledIfOn(OS[] disabledOnOs) {OS os = OS.determine();if (Arrays.asList(disabledOnOs).contains(os))return ConditionEvaluationResult.disabled("Test is disabled on " + os + ".");elsereturn ConditionEvaluationResult.enabled("Test is not disabled on " + os + ".");}}

我們可以如下使用它:

@Test @DisabledOnOs(OS.WINDOWS) void doesNotRunOnWindows() {assertTrue(false); }

真好

少禮

但是我們可以做得更好! 借助JUnit的可自定義注釋,我們可以使此條件更加平滑:

@TestExceptOnOs(OS.WINDOWS) void doesNotRunOnWindowsEither() {assertTrue(false); }

要實現@TestExceptOnOs,只需執行以下操作就可以了:

@Retention(RetentionPolicy.RUNTIME) @Test @DisabledOnOs(/* somehow get the `value` below */) public @interface TestExceptOnOs {OS[] value() default {};}

當執行測試并掃描OsCondition :: evaluateIfAnnotated中的@DisabledOnOs時,我們會發現它在@TestExceptOnOs上進行了元注釋,并且我們的邏輯將正常工作。 但是我找不到一種方法使@DisabledOnOs可以訪問提供給@TestExceptOnOs的OS值。 :( (你能?)

下一個最佳選擇是對新注釋簡單地使用相同的擴展名:

@Retention(RetentionPolicy.RUNTIME) @ExtendWith(OsCondition.class) @Test public @interface TestExceptOnOs {OS[] value() default {};}

然后我們拉皮條OsCondition :: evaluateIfAnnotated包括新的案例…

private ConditionEvaluationResult evaluateIfAnnotated(AnnotatedElement element) {Optional<DisabledOnOs> disabled = AnnotationUtils.findAnnotation(element, DisabledOnOs.class);if (disabled.isPresent())return disabledIfOn(disabled.get().value());Optional<TestExceptOnOs> testExcept = AnnotationUtils.findAnnotation(element, TestExceptOnOs.class);if (testExcept.isPresent())return disabledIfOn(testExcept.get().value());return ConditionEvaluationResult.enabled(""); }

……我們完成了。 現在我們確實可以按照我們希望的方式使用它。

拋光

創建倒置的注釋(如果不在指定的操作系統之一上禁用,則完全相同),但是有了它們,改進的名稱和靜態導入,我們可以在這里結束:

@TestOn(WINDOWS) void doesNotRunOnWindowsEither() {assertTrue(false); }

還不錯吧?

在CC-BY 2.0下由CWCS托管主機發布

@DisabledIfTestFails

讓我們再嘗試一件事–這次我們將使其變得非常有趣! 假設有很多(集成?)測試,并且如果其中一個測試由于特定的異常而失敗,那么其他測試也必然會失敗。 因此,為了節省時間,我們想禁用它們。

那么我們在這里需要什么呢? 顯而易見,我們必須以某種方式收集在測試執行過程中引發的異常。 這必須與測試類的生存期綁定,因此我們不會禁用測試,因為某些異常會在完全不同的測試類中發生。 然后,我們需要一個條件實現,該條件實現檢查是否拋出了特定異常,如果存在則禁用測試。

收集例外

查看擴展點列表,我們發現“異常處理”。 相應的接口看起來很有希望:

/*** ExceptionHandlerExtensionPoint defines the API for Extension Extensions* that wish to react to thrown exceptions in tests.** [...]*/ public interface ExceptionHandlerExtensionPoint extends ExtensionPoint {/*** React to a throwable which has been thrown by a test method.** Implementors have to decide if they* * - Rethrow the incoming throwable* - Throw a newly constructed Exception or Throwable* - Swallow the incoming throwable** [...]*/void handleException(TestExtensionContext context, Throwable throwable)throws Throwable; }

因此,我們將實現handleException來存儲然后重新拋出異常。

您可能還記得我寫的有關擴展和狀態的內容:

引擎在實例化擴展時以及將實例保留多長時間時不做任何保證,因此它們必須是無狀態的。 他們需要維護的任何狀態都必須寫入JUnit并從中加載。

好的,所以我們使用商店。 有效地收集了我們想要記住的東西。 我們可以通過傳遞給大多數擴展方法的擴展上下文來訪問它。 稍作修改后發現,每個上下文都有其自己的存儲,因此我們必須決定訪問哪個上下文。

每個測試方法(TestExtensionContext)和整個測試類(ContainerExtensionContext)都有一個上下文。 請記住,我們想將在執行所有測試期間拋出的所有異常存儲在一個類中,但不能存儲更多,即不存儲其他測試類拋出的異常。 事實證明,ContainerExtensionContext及其存儲正是我們需要的。

因此,這里我們獲取容器上下文并使用它來存儲一組引發的異常:

private static final Namespace NAMESPACE = Namespace.of("org", "codefx", "CollectExceptions"); private static final String THROWN_EXCEPTIONS_KEY = "THROWN_EXCEPTIONS_KEY";@SuppressWarnings("unchecked") private static Set<Exception> getThrown(ExtensionContext context) {ExtensionContext containerContext = getAncestorContainerContext(context).orElseThrow(IllegalStateException::new);return (Set<Exception>) containerContext.getStore(NAMESPACE).getOrComputeIfAbsent(THROWN_EXCEPTIONS_KEY,ignoredKey -> new HashSet<>()); }private static Optional<ExtensionContext> getAncestorContainerContext(ExtensionContext context) {Optional<ExtensionContext> containerContext = Optional.of(context);while (containerContext.isPresent()&& !(containerContext.get() instanceof ContainerExtensionContext))containerContext = containerContext.get().getParent();return containerContext; }

現在添加一個異常很簡單:

@Override public void handleException(TestExtensionContext context, Throwable throwable)throws Throwable {if (throwable instanceof Exception)getThrown(context).add((Exception) throwable);throw throwable; }

實際上,這本身就是一個有趣的擴展。 也許它也可以用于分析。 無論如何,我們將要查看拋出的異常,因此我們需要一個公共方法:

public static Stream<Exception> getThrownExceptions(ExtensionContext context) {return getThrown(context).stream(); }

有了這個擴展,任何其他擴展都可以檢查到目前為止已經拋出了哪些異常。

禁用

其余部分與以前非常相似,因此讓我們快速了解一下:

@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @ExtendWith(DisabledIfTestFailedCondition.class) public @interface DisabledIfTestFailedWith {Class<? extends Exception>[] value() default {};}

請注意,我們僅在方法上允許使用此注釋。 在測試類上使用它可能很有意義,但現在讓我們保持簡單。 因此,我們僅實現TestExecutionCondition。 在檢查了是否存在我們的注釋之后,我們使用用戶提供的異常類調用disableIfExceptionWasThrown:

private ConditionEvaluationResult disableIfExceptionWasThrown(TestExtensionContext context,Class<? extends Exception>[] exceptions) {return Arrays.stream(exceptions).filter(ex -> wasThrown(context, ex)).findAny().map(thrown -> ConditionEvaluationResult.disabled(thrown.getSimpleName() + " was thrown.")).orElseGet(() -> ConditionEvaluationResult.enabled("")); }private static boolean wasThrown(TestExtensionContext context, Class<? extends Exception> exception) {return CollectExceptionExtension.getThrownExceptions(context).map(Object::getClass).anyMatch(exception::isAssignableFrom); }

把它放在一起

如果在之前拋出特定類型的異常,這就是我們使用這些批注禁用測試的方式:

@CollectExceptions class DisabledIfFailsTest {private static boolean failedFirst = false;@Testvoid throwException() {System.out.println("I failed!");failedFirst = true;throw new RuntimeException();}@Test@DisabledIfTestFailedWith(RuntimeException.class)void disableIfOtherFailedFirst() {System.out.println("Nobody failed yet! (Right?)");assertFalse(failedFirst);}}

摘要

哇,那是很多代碼! 但是到目前為止,我們真的知道如何在JUnit 5中實現條件:

  • 創建所需的注釋和@ExtendWith條件實現
  • 實現ContainerExecutionCondition,TestExecutionCondition或同時實現
  • 檢查是否存在新的注釋
  • 進行實際檢查并返回結果

我們還看到,這可以與其他擴展點結合使用,如何使用商店來保留信息,并且自定義注釋可以使擴展使用起來更加優雅。

有關標記擴展點的更多樂趣,請在討論參數注入時查看本系列的下一篇文章。

翻譯自: https://www.javacodegeeks.com/2016/05/junit-5-conditions.html

junit5和junit4

總結

以上是生活随笔為你收集整理的junit5和junit4_JUnit 5 –条件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。