Realize source code analysis of junitperf based on junit5

老马啸西风
中文

Preface

The previous section introduced the implementation of junitperf based on junit4, but it can be found that the way of defining variables is still not elegant enough.

Can that make it more natural for users?

Yes, junit5 brings us more powerful functions.

Further reading:

Talking about performance testing

analyzes the source code of junitperf based on junit4, a secret that 99% of people don’t know about junit4!

junit5

No comparison, no harm

Let's first review the writing of 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);
    }

}

Let's take a look at the writing of junit5:

public class HelloWorldTest {

    @JunitPerfConfig(duration = 1000)
    public void helloTest() throws InterruptedException {
        Thread.sleep(100);
        System.out.println("Hello Junit5");
    }

}

JunitPerfRule magically disappeared? How did all this happen?

Let us uncover the mystery of junit5 together.

Junit5 more powerful features

@JunitPerfConfig

We just specified a simple @JunitPerfConfig annotation, then the problem must lie in this annotation.

It is defined as follows:

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 and @Target are regular annotations in java, so I won’t repeat them here.

Let's focus on the remaining two notes.

@TestTemplate

When we used to write unit tests, we always wrote a @Test annotation. You will find that even this annotation is omitted in junit5.

So, where did he go?

The answer is @TestTemplate statement, which is used to identify that this method is a unit test method, and idea will recognize it, which is very flexible and powerful.

@ExtendWith

This annotation empowers our annotation.

Look at the name, it is an extension, the implementation of extension is the class PerfConfigProvider we specify

PerfConfigProvider

Let's take a look at the implementation of 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));
    }

}

The implementation is very simple, the first is a filter.

Only @JunitPerfConfig annotations will take effect.

The following is the context PerfConfigContext of our custom implementation.

PerfConfigContext

PerfConfigContext implements TestTemplateInvocationContext and simply encapsulates the native 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);
                    }
                }
        );
    }
}

After writing this, we will find that it has returned to the similarity with junit4.

Friends who don't understand can go to see the original implementation, so I won't go into details here.

The rest is the same as the original junit4 implementation.

summary

It can be found that the expansion capabilities provided by junit5 are more powerful and flexible. It allows us to define our own annotations.

This annotation is used to make the user no different from using the original junit5 annotation.

I have to sigh with emotion that the back wave of the Yangtze River pushed the front wave, and the front wave died on the beach.

Reference

https://github.com/houbb/junitperf

https://github.com/junit-team/junit4/wiki/Rules

阅读 190

java 工具
整理 java 开发过程中有用的工具
120 声望
14 粉丝
0 条评论
你知道吗?

120 声望
14 粉丝
宣传栏