基于 junit5 实现 junitperf 源码分析
前言
上一节介绍了基于 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 注解没有什么区别。
不得不感慨一句,长江后浪推前浪,前浪死在沙滩上。
参考资料
https://github.com/houbb/junitperf
https://github.com/junit-team/junit4/wiki/Rules
基于 junit5 实现 junitperf 源码分析的更多相关文章
- Django——基于类的视图源码分析 二
源码分析 抽象类和常用视图(base.py) 这个文件包含视图的顶级抽象类(View),基于模板的工具类(TemplateResponseMixin),模板视图(TemplateView)和重定向视图 ...
- SPI机制剖析——基于DriverManager+ServiceLoader的源码分析
我的上一篇博客类加载器与双亲委派中提到,SPI机制是一种上级类加载器调用下级类加载器的情形,因此会打破类加载的双亲委派模型.为了深入理解其中的细节,本博客详细剖析一下SPI机制,并以JDBC为例,基于 ...
- Django——基于类的视图源码分析 一
基于类的视图(Class-based view)是Django 1.3引入的新的视图编写方式,用于取代以前基于函数(Function-based)方式. 借助于OO和Python中方便的多重继承特性, ...
- Django——基于类的视图源码分析 三
列表类通用视图(list.py) 此文件包含用于显示数据列表常用的类和工具类.不仅可以方便的用于显示基于模型(Model)的数据列表,也可以用于显示自定义数据列表. 此图中绿色部分属于base.py, ...
- documentsUI源码分析
documentsUI源码分析 本文基于Android 6.0的源码,来分析documentsUI模块. 原本基于7.1源码看了两天,但是Android 7.1与6.0中documentsUI模块差异 ...
- Spark大师之路:广播变量(Broadcast)源码分析
概述 最近工作上忙死了……广播变量这一块其实早就看过了,一直没有贴出来. 本文基于Spark 1.0源码分析,主要探讨广播变量的初始化.创建.读取以及清除. 类关系 BroadcastManager类 ...
- 第八篇:Spark SQL Catalyst源码分析之UDF
/** Spark SQL源码分析系列文章*/ 在SQL的世界里,除了官方提供的常用的处理函数之外,一般都会提供可扩展的对外自定义函数接口,这已经成为一种事实的标准. 在前面Spark SQL源码分析 ...
- HashMap源码分析(一)
基于JDK1.7 HashMap源码分析 概述 HashMap是存放键值对的集合,数据结构如下: table被称为桶,大小(capacity)始终为2的幂,当发生扩容时,map容量扩大为两倍 Hash ...
- java集合源码分析(六):HashMap
概述 HashMap 是 Map 接口下一个线程不安全的,基于哈希表的实现类.由于他解决哈希冲突的方式是分离链表法,也就是拉链法,因此他的数据结构是数组+链表,在 JDK8 以后,当哈希冲突严重时,H ...
- docker 源码分析 一(基于1.8.2版本),docker daemon启动过程;
最近在研究golang,也学习一下比较火的开源项目docker的源代码,国内比较出名的docker源码分析是孙宏亮大牛写的一系列文章,但是基于的docker版本有点老:索性自己就git 了一下最新的代 ...
随机推荐
- git添加被.gitignore忽略的文件
技术背景 在git操作中,有时候为了保障线上分支的简洁性,会在.gitignore文件中屏蔽一些关键词,比如可以加一个*.txt来屏蔽掉项目中所有带txt后缀的文件,还可以加上*test*来屏蔽所有的 ...
- [转贴]BLOCKED,WAITING,TIMED_WAITING有什么区别?-用生活的例子解释
BLOCKED,WAITING,TIMED_WAITING有什么区别?-用生活的例子解释 https://www.jianshu.com/p/0976b2f23db1 https://dzone.co ...
- 在K8S中,静态、动态、自主式Pod有何区别?
在Kubernetes(简称K8s)中,静态Pod.自主式Pod和动态Pod是不同管理方式下的Pod类型,它们的区别主要体现在创建和管理方式上: 静态Pod: 静态Pod是由kubelet直接管理的, ...
- 🛠 开源即时通讯(IM)项目OpenIM源码部署指南
OpenIM的部署涉及多个组件,并支持多种方式,包括源码.Docker和Kubernetes等.这要求在确保不同部署方式之间的兼容性同时,还需有效管理各版本之间的差异.确实,这些都是复杂的问题,涉及到 ...
- vim 从嫌弃到依赖(13)——motion 进阶
在最开始的时候我们介绍了一些vim中的motion 包括如何在字符间.单词间.行间以及多行间移动.·但是motion中的内容可远不止我们介绍的这些,平时用到的也远不止之间介绍的那些. 之所以没有一次介 ...
- 1.2 w字+!Java IO 基础知识系统总结 | JavaGuide
首发于:JavaGuide(「Java学习+面试指南」一份涵盖大部分 Java 程序员所需要掌握的核心知识.) 原文地址:https://javaguide.cn/java/io/io-basis.h ...
- SqlSugar基础查询
查所有 List<Student> list=db.Queryable<Student>().ToList() //select * from Student 查询总数 int ...
- 强化学习从基础到进阶-常见问题和面试必知必答[3]:表格型方法:Sarsa、Qlearning;蒙特卡洛策略、时序差分等以及Qlearning项目实战
强化学习从基础到进阶-常见问题和面试必知必答[3]:表格型方法:Sarsa.Qlearning:蒙特卡洛策略.时序差分等以及Qlearning项目实战 1.核心词汇 概率函数和奖励函数:概率函数定量地 ...
- python入门之后须掌握的知识点(模块化编程、时间模块)【一】
相关文章: 全网最详细超长python学习笔记.14章节知识点很全面十分详细,快速入门,只用看这一篇你就学会了! python入门合集: python快速入门[一]-----基础语法 python快速 ...
- Python 实现指定窗口置顶激活
通过Python实现对特定窗口的置顶操作以及对特定窗体发送按键,这里需要安装一个第三方pip包,执行命令pywin32安装好以后,我们运行试试. 第一个案例,遍历所有句柄,然后对特定窗口进行最大化或最 ...