前言
上一節介紹了基於 junit4 實現 junitperf,但是可以發現定義變數的方式依然不夠優雅。
那可以讓使用者使用起來更加自然一些嗎?
有的,junit5 為我們帶來了更加強大的功能。
擴充閱讀:
基於 junit4 分析 junitperf 原始碼,junit4 99% 的人都不知道的祕密!
沒有對比,就沒有傷害
我們首先回顧一下 junit4 的寫法:
public class HelloWorldTest {
@Rule
public JunitPerfRule junitPerfRule = new JunitPerfRule();
/**
* 單一執行緒,執行 1000ms,預設以 html 輸出測試結果
* @throws InterruptedException if any
*/
@Test
@JunitPerfConfig(duration = 1000)
public void helloWorldTest() throws InterruptedException {
System.out.println("hello world");
Thread.sleep(20);
}
}
複製程式碼
再看一下 junit5 的寫法:
public class HelloWorldTest {
@JunitPerfConfig(duration = 1000)
public void helloTest() throws InterruptedException {
Thread.sleep(100);
System.out.println("Hello Junit5");
}
}
複製程式碼
JunitPerfRule 竟然神奇的消失了?這一切是怎麼做到的呢?
讓我們一起揭開 junit5 神祕的面紗。
Junit5 更加強大的特性
@JunitPerfConfig
我們只是指定了一個簡單的 @JunitPerfConfig
註解,那麼問題一定就出在這個註解裡。
定義如下:
import java.lang.annotation.*;
/**
* 執行介面
* 對於每一個測試方法的條件配置
* @author bbhou
* @version 1.0.0
* @since 1.0.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@ExtendWith(PerfConfigProvider.class)
@TestTemplate
public @interface JunitPerfConfig {
// 屬性省略
}
複製程式碼
@Retention
和 @Target
屬於 java 中的常規註解,此處不做贅述。
我們重點看一下剩餘的兩個註解。
@TestTemplate
我們以前在寫單元測試的時候,都會寫一個 @Test
註解,你會發現 junit5 中連這個註解都省略了。
那麼,他去哪裡了呢?
答案就是 @TestTemplate
宣告的註解,就是用來標識這個方法是單元測試的方法,idea 也會認的,這一點非常的靈活強大。
@ExtendWith
這個註解,給我們的註解進行了賦能。
看名字,就是一個擴充,擴充的實現,就是我們指定的類 PerfConfigProvider
PerfConfigProvider
我們來看一下 PerfConfigProvider 的實現。
public class PerfConfigProvider implements TestTemplateInvocationContextProvider {
@Override
public boolean supportsTestTemplate(ExtensionContext context) {
return context.getTestMethod()
.filter(m -> AnnotationSupport.isAnnotated(m, JunitPerfConfig.class))
.isPresent();
}
@Override
public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(ExtensionContext context) {
return Stream.of(new PerfConfigContext(context));
}
}
複製程式碼
實現非常簡單,首先是一個過濾。
只有定義了 @JunitPerfConfig
註解的方法,才會生效。
下面就是我們自定義實現的上下文 PerfConfigContext。
PerfConfigContext
PerfConfigContext 實現了 TestTemplateInvocationContext,並且對原生的 ExtensionContext 進行了簡單的封裝。
public class PerfConfigContext implements TestTemplateInvocationContext {
// 省略內部屬性
@Override
public List<Extension> getAdditionalExtensions() {
return Collections.singletonList(
(TestInstancePostProcessor) (testInstance, context) -> {
final Class clazz = testInstance.getClass();
// Group test contexts by test class
ACTIVE_CONTEXTS.putIfAbsent(clazz, new ArrayList<>());
EvaluationContext evaluationContext = new EvaluationContext(testInstance,
method,
DateUtil.getCurrentDateTimeStr());
evaluationContext.loadConfig(perfConfig);
evaluationContext.loadRequire(perfRequire);
StatisticsCalculator statisticsCalculator = perfConfig.statistics().newInstance();
Set<Reporter> reporterSet = getReporterSet();
ACTIVE_CONTEXTS.get(clazz).add(evaluationContext);
try {
new PerformanceEvaluationStatement(evaluationContext,
statisticsCalculator,
reporterSet,
ACTIVE_CONTEXTS.get(clazz),
clazz).evaluate();
} catch (Throwable throwable) {
throw new JunitPerfRuntimeException(throwable);
}
}
);
}
}
複製程式碼
寫到這裡,我們就會發現又回到了和 junit4 相似的地方。
不明白的小夥伴可以去看一下原來的實現,這裡不做贅述。
剩下的部分,和原來 junit4 的實現都是一致的。
小結
可以發現 junit5 為我們提供的擴充能力更加強大靈活,他可以讓我們定義屬於自己的註解。
這個註解用起來讓使用者和使用原有的 junit5 註解沒有什麼區別。
不得不感慨一句,長江後浪推前浪,前浪死在沙灘上。