preface

The last section introduced junitPerf based on junit4, but you can see that the way you define variables is still not elegant enough.

Does that make it more natural for users to use?

Yes, junit5 brings us even more power.

Read more:

On Performance Testing

Junit4 based on junit4 analysis junitperf source code, junit4 99% of people do not know the secret!

No comparison, no harm

Let’s first review how junit4 is written:

public class HelloWorldTest {

    @Rule
    public JunitPerfRule junitPerfRule = new JunitPerfRule();

    /** * single thread, 1000ms, default output test results in HTML *@throws InterruptedException if any
     */
    @Test
    @JunitPerfConfig(duration = 1000)
    public void helloWorldTest(a) throws InterruptedException {
        System.out.println("hello world");
        Thread.sleep(20); }}Copy the code

Let’s see how junit5 is written:

public class HelloWorldTest {

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

JunitPerfRule magically disappeared? How does all this work?

Let’s unravel the mystery of junit5.

Junit5’s more powerful features

@JunitPerfConfig

We just specified a simple @junitperfConfig annotation, so the problem must be in that annotation.

The definition is as follows:

import java.lang.annotation.*;

/** * Execute interface * for each test method condition configuration *@author bbhou
 * @version 1.0.0
 * @since1.0.0 * /
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})

@ExtendWith(PerfConfigProvider.class)
@TestTemplate
public @interface JunitPerfConfig {

    // Attribute omission

}
Copy the code

@Retention and @Target are common Java annotations and will not be covered here.

Let’s focus on the remaining two notes.

@TestTemplate

We used to write a @test annotation when we were writing unit tests, and you’ll notice that junit5 omitted even this annotation.

So where did he go?

The answer is that the @testTemplate annotation, which is used to identify the method as a unit test, is very flexible and powerful.

@ExtendWith

This annotation enables our annotation.

If you look at the name, it’s an extension, the implementation of the extension, which is the class PerfConfigProvider that we specified

PerfConfigProvider

Let’s take a look at the PerfConfigProvider implementation.

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(newPerfConfigContext(context)); }}Copy the code

The implementation is very simple, starting with a filter.

The @junitperfConfig annotation takes effect only if the method is defined.

Here is the context PerfConfigContext for our custom implementation.

PerfConfigContext

PerfConfigContext TestTemplateInvocationContext is achieved, and the native ExtensionContext has carried on the simple packaging.

public class PerfConfigContext implements TestTemplateInvocationContext {

    // Omit the internal attributes

    @Override
    public List<Extension> getAdditionalExtensions(a) {
        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 newJunitPerfRuntimeException(throwable); }}); }}Copy the code

At this point, we find ourselves back on the same page as junit4.

Do not understand the small partners can go to see the original implementation, here do not repeat.

The rest is consistent with the original junit4 implementation.

summary

You can see that junit5 gives us a much more flexible extension that allows us to define our own annotations.

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

Have to sigh a sentence, the Yangtze River after the wave push the wave before, before the wave died on the beach.

The resources

Github.com/houbb/junit…

Github.com/junit-team/…