Junit 5 Extension Vs Features

With every release, the Development team wants to implement as many new features as they can, to provide an overall possible case in its core functionality. but JUnit begs to differ, JUnit core principals are.

It's better to enable new functionality by creating or augmenting an extension point rather than adding the functionality as a core feature.

reasons

  • A handful of developers cannot cover all possible scenarios.
  • Third-party developers can provide extensive insights and develop really faster.
  • Because of so wast amount of users, it's hard to maintain or depreciate a feature, but for 3rd party developers, it's easy.

So instead of providing new features for every possible case, the JUnit team provides extensions that can be implemented by build tool vendors, development tools, or simply test case writers to create a new feature.

JUnit 5 Extentions

An extension point in Junit 5 test life cycle is a callback interface extending org.junit.jupiter.api.extension.Extension interface that can be implemented and register with JUnit.

  • BeforeAllCallback

Classes implementing BeforeAllCallback interface will execute and provide additional behavior before all test cases invoke.

  • BeforeEachCallback

Classes implementing BeforeEachCallback interface will execute and provide additional behavior before each test case invoke.

  • BeforeTestExecutionCallback

Classes implementing BeforeTestExecutionCallback interface will execute and provide additional behavior just before executing the test case.

  • AfterTestExecutionCallback

Classes implementing AfterTestExecutionCallback interface will execute and provide additional behavior just after executing the test case

  • AfterEachCallback

Classes implementing AfterEachCallback interface will execute and provide additional behavior after executing the test case

  • AfterAllCallback

Classes implementing AfterAllCallback interface will execute and provide additional behavior after executing all test cases.

  • TestExecutionExceptionHandler

Classes implementing TestExecutionExceptionHandler interface will execute and provide additional behavior if an exception occurred and not handled properly while executing test cases.

  • ParameterResolver

Classes implementing ParameterResolver interface will execute and provide additional behavior before executing parameterized test cases.

Activating an extension

All extensions created in JUnit 5 must be registered and activated with JUnit in order for them to execute. JUnit provides @ExtendWith annotation. All extensions which need to be activated must be registered with @ExtendWith annotation.

package com.example.junit5.sujan;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;

public class AppleCalculator {
    List<String> apples = Arrays.asList("McIntosh", "Fuji", "Gala", "Jonagold", "GrannySmith", "PinkLady");

    public int addApple(int apple1, int apple2) {
        return apple1 + apple2;
    }

    public String getError(String apple) {
        if (Objects.isNull(apple)) {
            throw new NullPointerException("apple cannot be null");
        }
        return apple;
    }

    public boolean isApple(String appleName) {
        return apples.contains(appleName);
    }
}
package com.example.junit5.sujan;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

@ExtendWith({TestExecutionExceptionHandlerImpl.class, ParameterResolverImpl.class, BeforeTestExecutionCallbackImpl.class, BeforeEachCallbackImpl.class, AfterEachCallbackImpl.class, AfterTestExecutionCallbackImpl.class, BeforeAllCallbackImpl.class, AfterAllCallbackImpl.class, AfterAllCallbackImpl.class})
class AppleCalculatorTest {
    @AfterAll
    static void afterAll() {
        System.out.println("AppleCalculatorTest.afterAll");
    }

    @BeforeAll
    static void beforeAll() {
        System.out.println("AppleCalculatorTest.beforeAll");
    }

    @BeforeEach
    void beforeEach() {
        System.out.println("AppleCalculatorTest.beforeEach");
    }

    @AfterEach
    void afterEach() {
        System.out.println("AppleCalculatorTest.afterEach");
    }

    @Test
    void addAppleTest() {
        System.out.println("AppleCalculatorTest.addAppleTest");
        AppleCalculator appleCalculator = new AppleCalculator();
        assertEquals(2, appleCalculator.addApple(1, 1), "1 apple + 1 apple is 2 apple");
    }

    @Test
    void assertThrowTest() {
        AppleCalculator appleCalculator = new AppleCalculator();
        appleCalculator.getError(null);
    }

    @ParameterizedTest
    @ValueSource(strings = {"McIntosh", "Mango", "Fuji", "Orange", "Gala"})
    void isAppleTest(String appleName) {
        AppleCalculator appleCalculator = new AppleCalculator();
        assertTrue(appleCalculator.isApple(appleName), "yes its an apple");
    }
}
package com.example.junit5.sujan;

import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

public class BeforeAllCallbackImpl implements BeforeAllCallback {
    @Override
    public void beforeAll(ExtensionContext context) throws Exception {
        System.out.println("BeforeAllCallbackImpl.beforeAll");
    }
}
package com.example.junit5.sujan;

import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

public class BeforeEachCallbackImpl implements BeforeEachCallback {
    @Override
    public void beforeEach(ExtensionContext context) {
        System.out.println("BeforeEachCallbackImpl.beforeEach");
    }
}
package com.example.junit5.sujan;

import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

public class BeforeTestExecutionCallbackImpl implements BeforeTestExecutionCallback {
    @Override
    public void beforeTestExecution(ExtensionContext context) throws Exception {
        System.out.println("BeforeTestExecutionCallbackImpl.beforeTestExecution");
    }
}
package com.example.junit5.sujan;

import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;

public class ParameterResolverImpl implements ParameterResolver {
    @Override
    public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
        System.out.println("ParameterResolverImpl.supportsParameter");
        return true;
    }

    @Override
    public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
        System.out.println("ParameterResolverImpl.resolveParameter");
        return null;
    }
}
package com.example.junit5.sujan;

import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestExecutionExceptionHandler;

public class TestExecutionExceptionHandlerImpl implements TestExecutionExceptionHandler {
    @Override
    public void handleTestExecutionException(ExtensionContext context, Throwable throwable) {
        System.out.println("TestExecutionExceptionHandlerImpl.handleTestExecutionException");
    }
}
package com.example.junit5.sujan;

import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

public class AfterTestExecutionCallbackImpl implements AfterTestExecutionCallback {
    @Override
    public void afterTestExecution(ExtensionContext context) throws Exception {
        System.out.println("AfterTestExecutionCallbackImpl.afterTestExecution");
    }
}
package com.example.junit5.sujan;

import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

public class AfterEachCallbackImpl implements AfterEachCallback {
    @Override
    public void afterEach(ExtensionContext context) throws Exception {
        System.out.println("AfterEachCallbackImpl.afterEach");
    }
}
package com.example.junit5.sujan;

import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

public class AfterAllCallbackImpl implements AfterAllCallback {
    @Override
    public void afterAll(ExtensionContext context) throws Exception {
        System.out.println("AfterAllCallbackImpl.afterAll");
    }
}

 

follow us on