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");
}
}