• 基于 junit5 实现 junitperf 源码分析


    前言

    上一节介绍了基于 junit4 实现 junitperf,但是可以发现定义变量的方式依然不够优雅。

    那可以让用户使用起来更加自然一些吗?

    有的,junit5 为我们带来了更加强大的功能。

    拓展阅读:

    浅谈性能测试

    基于 junit4 分析 junitperf 源码,junit4 99% 的人都不知道的秘密!

    junit5

    没有对比,就没有伤害

    我们首先回顾一下 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

  • 相关阅读:
    老外写的js闭包
    List<Object> 转为 List<MyClass>
    html 自定义属性
    js 中的算术运算
    System.Web.Mvc.Html 命名空间小计
    历时半年,发布最完整的代码生成器CodeBuilder最新版本
    CodeBuilder之Template接口
    CodeBuilder之Tool接口
    FaibClass.Data
    轻量的Json序列化
  • 原文地址:https://www.cnblogs.com/houbbBlogs/p/15054755.html
Copyright © 2020-2023  润新知