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