5

基于 junit5 实现 junitperf 源码分析

 2 years ago
source link: https://segmentfault.com/a/1190000040396896
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

基于 junit5 实现 junitperf 源码分析

发布于 今天 03:19

上一节介绍了基于 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/juni...

https://github.com/junit-team...


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK