class ts 扩展方法_JUnit 5自定义扩展
前言
在org.junit.jupiter.api.extension包下,JUnit5提供了豐富的擴展接口,通過實現這些接口,我們可以定制自己的擴展并注冊到JUnit中來實現功能擴展。
Extension接口
這個接口可以說是JUnit擴展中最為重要的接口,不過與它的重要性不相匹配的是,它沒有定義任何的成員:
public interface Extension { }然而它的子接口卻極其豐富:
注冊擴展的方式
前面說過,我們可以通過實現Extension的子接口來定制自己的擴展,那么注冊又是如何做到的呢?在JUnit5中提供了兩個注解來幫助我們將自定義擴展注冊到JUnit,它們分別是:@ExtendWith和@RegisterExtension。
- @ExtendWith
這個注解可標注在類型或方法上,通過聲明式的方式注冊擴展。是可重復注解的同時,又接受一個Extension類型的數組,當存在多個擴展時,你可在數組中傳入多個Extension,抑或是結合@Extensions注解使用:
@Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Repeatable(Extensions.class) public @interface ExtendWith {Class<? extends Extension>[] value(); }- @RegisterExtension
這個注解也是用來注冊擴展的,但是它只能被用到字段上,且相對于@ExtendWith的聲明式注冊方式,它是編程式的注冊方式。被它標注的字段可以是static或non-static,但這個字段不能被private修飾,實際的值也不能為null:
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RegisterExtension { }另外,對于被static修飾和不被static修飾也要分情況討論:
- static:通過這種方式注冊的擴展不受任何限制,你可以注冊BeforeAllCallback、AfterAllCallback、TestInstanceFactory、TestInstancePostProcessor、TestInstancePreDestroyCallback、BeforeEachCallback等等類型。
- non-static:這種實例類型的注冊往往會被延遲,它會在測試類實例化完成并且方法級別的@ExtendWith都注冊之后,這回導致一些類級別或實例級別的擴展如:BeforeAllCallback、AfterAllCallback、TestInstanceFactory、TestInstancePostProcessor的注冊出現問題。但是,如果你在測試類上標注了@TestInstance(Lifecycle.PER_CLASS),那么它將會被提前到方法級別的@ExtendWith注冊之前注冊。
@RegisterExtension標注的字段注冊順序是根據算法確定的,如果你想要明確他們的注冊順序,可以使用org.junit.jupiter.api.Order注解指定。
聲明式 Vs 編程式
現在有必要考慮一個問題:聲明式的注冊意味著什么?為什么需要編程式的注冊?
首先聲明式注冊的擴展都不支持手動調用擴展類的構造方法或工廠方法等傳入參數,意味著它們的行為將無法定制,因而存在一定的局限性;由此才引出了編程式的注冊方法,我們可以通過擴展的構造器或者工廠方法等傳入參數,從而實現進一步的擴展定制!
這樣一來我們便可知道,聲明式有它的便利之處,而編程式也有它的強大之處,沒有孰優孰劣,都有自己的適用場景。
注冊示例
JUnit支持我們對異常做擴展,一個測試方法中可能會拋出異常,而這異常會被JUnit捕獲。通過Extension下的子接口TestExecutionExceptionHandler,我們可以決定在捕獲異常之后的行為。
由于@ExtendWith使用簡單,且在其它文章中已多次用到,這里就不再贅述,只講@RegisterExtension。先在測試類中創建一個ExceptionHandler:
static class ExceptionHandler implements TestExecutionExceptionHandler {private String message;ExceptionHandler(String message) {this.message = message;}@Overridepublic void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable {throw new RuntimeException(String.format("Display name: [%s], reason: [%s], raw message: [%s]",context.getDisplayName(), this.message, throwable.getMessage()));}}之后通過字段方式注冊它,同時寫一個普通的測試方法,拋出一個異常:
class JunitSampleTests {static class ExceptionHandler implements TestExecutionExceptionHandler {// ...}@RegisterExtensionstatic ExceptionHandler exceptionHandler = new ExceptionHandler("異常被捕獲了");@Testvoid test() {throw new RuntimeException("測試出錯啦!");} }注意上面調用了ExceptionHandler的構造器傳入了message,這是聲明式的@ExtendWith無法做到的:
SPI注冊
不知你是否了解過Java中的SPI(Service Provider Interface)機制,它可以用來啟用框架擴展和替換組件,這在JUnit中是支持的,借此我們可以在不使用注解的情況下注冊我們的擴展。
如果你是Maven工程,需要在test目錄下的測試資源目錄resources(這個目錄一般不存在,需要手動創建并右鍵標記為“Test Resources Root”)中新建一個名為junit-platform.properties的文件(這個文件名不能隨意,否則JUnit無法掃描到),并在其中加上配置:
junit.jupiter.extensions.autodetection.enabled=true而后同樣在這個resources下,新建目錄WEB-INF/services,之后創建一個名為org.junit.jupiter.api.extension.Extension的文件,這個文件名其實就是Extension接口的全限定類名,而其中的內容就是我們實現的擴展類的全限定類名(如有多個擴展實現,一個限定名占一行):
com.tinysand.fileuploads.ExceptionHandler這里我把之前的擴展實現單獨提成了一個類文件,同時去掉了帶參的構造器和成員,顯然這種方式也只能像@ExtendWith注解做的那樣。
最后,如果不想使用配置文件,你可以在VM(Run/Debug Configurations中的VM options)參數添加如下參數而達到同樣的效果:
-Djunit.jupiter.extensions.autodetection.enabled=true軟件版本
| JUnit | 5.6.2(junit-jupiter) |
總結
以上是生活随笔為你收集整理的class ts 扩展方法_JUnit 5自定义扩展的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: b+树阶怎么确定_你知道危险品运输是怎么
- 下一篇: x722网卡支持百兆吗_同样是无线网卡,