Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Writing Tests With JUnit 5 and CDI 2.0

DZone's Guide to

Writing Tests With JUnit 5 and CDI 2.0

This post provides a guide to JUnit's most recent release and its new features, with sample code for the updated assertions and extensions.

· DevOps Zone ·
Free Resource

The need for DevOps innovation has never been greater. Get the results from over 100 business value assessments in this whitepaper, Digital Darwinism: Driving Digital Transformation, to see the positive impact of DevOps first hand.

JUnit is the most popular test framework in the Java world. In the newest release, version 5.0.3, it brings new features that will make Java developers' lives more comfortable. It has Java 8 as a minimum requirement that allows further support for Java 8. This article will cover a simple sample with JUnit integrated with CDI 2.0.

In this version, there is break compatibility, such as the package org.junit.jupiter.api instead of org.junit:

JUnit 4 Junit 5

Assert

Assertions

Assume

Assumptions

@Before

@BeforeEach

@After

@AfterEach

@BeforeClass

@BeforeAll

@AfterClass

@AfterAll

@Ignore

@Disable

@Category

@Tag

@RunWith, @Rule and @ClassRule

@ExtendeWith


To set up JUnit 5.0 in a Maven project:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.soujava</groupId>
    <artifactId>jnunit</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>JUnit 5 set dependency</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.0.3</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.19.1</version>
                <dependencies>
                    <dependency>
                        <groupId>org.junit.platform</groupId>
                        <artifactId>junit-platform-surefire-provider</artifactId>
                        <version>1.0.3</version>
                    </dependency>
                </dependencies>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>


With the dependency defined, your project is ready to use JUnit 5:

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;


@DisplayName("Hello world test")
public class HelloWorldTest {


    @BeforeAll
    public static void beforeAll() {
        System.out.println("Before all");
    }

    @AfterAll
    public static void afterAll() {
        System.out.println("After all");
    }

    @BeforeEach
    public void beforeEach() {
        System.out.println("Before each test");
    }

    @AfterEach
    public void afterEach() {
        System.out.println("Before after test");
    }


    @Test
    @DisplayName("should returns equals values")
    public void shouldEquals() {
        Assertions.assertEquals(5, 2 + 3);
    }

    @Test
    @DisplayName("should returns not equals values")
    public void shouldNotEquals() {
        Assertions.assertNotEquals("Brazil", "Argetina");
    }

    @Test
    @DisplayName("should be not null")
    public void shouldNotNull() {
        Assertions.assertNotNull("Brazil");
    }
}


Image title

In this version, there is Lambda support, such as Assertions.assertAll and Assertions.assertTimeout, which both expect an Executable interface, as an interface with one single method that is a functional interface:

public class JunitWitJava8Support {

    @Test
    @DisplayName("That breaks compatibility instead of @Test(expected = NullPointerException.class)")
    public void shouldReturnNPE() {
        Assertions.assertThrows(NullPointerException.class, () -> {
            throw new NullPointerException();
        });
    }

    @Test
    public void shouldCheckErrorMessage() {
        String errorMessage = "Error message";
        NullPointerException exception = Assertions.assertThrows(NullPointerException.class, () -> {
            throw new NullPointerException(errorMessage);
        });
        Assertions.assertEquals(errorMessage, exception.getMessage());
    }

    @Test
    public void shouldShouldExecute() {
        Assertions.assertAll(() -> {
            Assertions.assertTrue(Collections.emptyList().isEmpty());
        }, () -> {
            Assertions.assertNull(null);
        });
    }

    @Test
    public void shouldGetResult() {

        Process process = new Process();
        String result = Assertions.assertTimeout(Duration.ofMillis(2000), process::process);
        Assertions.assertEquals("Message result", result);

    }


    class Process {

        String process() throws Exception {
            Thread.sleep(1000);
            return "Message result";
        }
    }
}


Extensions

Follow the documentation about the extension in JUnit 5:

In contrast to the competing Runner, @Rule, and @ClassRule extension points in JUnit 4, the JUnit Jupiter extension model consists of a single, coherent concept: the Extension API. Note, however, that Extension itself is just a marker interface.

Using a Mockito extension, you can use it integrated with JUnit, as in JUnit 4:

@ExtendWith(MockitoExtension.class)
public class ExtenseionMockitoTest {

    @Mock
    private Team team;

    @BeforeEach
    public void beforeEach() {
        Mockito.when(team.getName()).thenReturn("Bahia");
    }

    @Test
    public void shouldEquals() {
        Assertions.assertEquals("Bahia", team.getName());
    }

    @Test
    public void shouldInjectByParam(@Mock Team team) {
        Assertions.assertNotNull(team);
    }

    interface Team {

        String getName();
    }
}


In this article, we're going to use your Extension, however, to CDI 2.0. Basically, this extension once has a field with @Inject it will inject using the SeContainer in CDI using the fields qualifiers.

public class CDIExtension implements TestInstancePostProcessor {


    private static final SeContainer CONTAINER = SeContainerInitializer.newInstance().initialize();
    private static final Predicate<Annotation> IS_QUALIFIER = a -> a.annotationType().isAnnotationPresent(Qualifier.class);

    @Override
    public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws IllegalAccessException {

        for (Field field : getFields(testInstance.getClass())) {
            if (field.getAnnotation(Inject.class) != null) {
                Annotation[] qualifiers = Stream.of(field.getAnnotations())
                        .filter(IS_QUALIFIER)
                        .toArray(Annotation[]::new);
                Object injected = CONTAINER.select(field.getType(), qualifiers).get();
                field.setAccessible(true);
                field.set(testInstance, injected);
            }
        }
    }

    private List<Field> getFields(Class<?> clazzInstance) {
        List<Field> fields = new ArrayList<>();
        if (!clazzInstance.getSuperclass().equals(Object.class)) {
            fields.addAll(getFields(clazzInstance.getSuperclass()));
        } else {
            fields.addAll(asList(clazzInstance.getDeclaredFields()));
        }
        return fields;
    }

}


Testing the Recommendation System

In the previous article, we discussed a system recommendation using Neo4J and EE4J now it's time to test it. In the code, there is a connection to Neo4J. However, a dependency on an external database does not seem like a good strategy, so for tests, we can use a Neo4J embedded database. Furthermore, this step creates an implementation of GraphProducer with the embedded database, then overrides to the external database. CDI handles it using the Alternatives annotation with higher priority:

@ApplicationScoped
@Alternative
@Priority(Interceptor.Priority.APPLICATION+10)
public class EmbeddedSupplier implements GraphSupplier {

    private Graph graph = Neo4jGraph.open(new File("").getAbsolutePath() + "/target/jnosql-graph");

    @Override
    @Produces
    public Graph get() {
        return graph;
    }
}


Concluding the embedded database, the next step is to create tests integrated with CDI:

@ExtendWith(CDIExtension.class)
public class CityRepositoryTest {

    @Inject
    @Database(DatabaseType.GRAPH)
    private CityRepository repository;

    @Test
    public void shouldFindById() {
        Name name =  Name.of("New York");
        City city = new City(name.get());

        repository.save(city);
        assertTrue(repository.findByName(name.get()).isPresent());
    }

    @Test
    public void shouldDeleteById() {
        Name name =  Name.of("New York");

        City city = new City(name.get());

        repository.save(city);
        assertTrue(repository.findByName(name.get()).isPresent());
        repository.deleteByName(name.get());
        assertFalse(repository.findByName(name.get()).isPresent());
    }

}


@ExtendWith(CDIExtension.class)
class BuddyServiceTest {

    @Inject
    private BuddyService service;

    @Inject
    private BuddyLoader loader;


    @BeforeEach
    public void setUp() {
        loader.loadVertex();
        loader.loadEdges();
    }

    @AfterEach
    public void after() {
        loader.clean();
    }


    @Test
    public void shouldFindByTechnology() {

        List<Buddy> javaDevelopers = service.findByTechnology(JAVA.getName());


        assertAll(() -> {
            assertFalse(javaDevelopers.isEmpty());
        }, () -> {
            assertEquals(2, javaDevelopers.size());
        }, () -> {
            Predicate<String> isJoao = "joao"::equalsIgnoreCase;
            Predicate<String> isJose = "jose"::equalsIgnoreCase;
            assertTrue(javaDevelopers.stream().map(Buddy::getDisplayName).allMatch(isJoao.or(isJose)));
        });
    }

}


References:

Interested in Kubernetes but unsure where to start? Check out this whitepaper, A Roundup of Managed Kubernetes Platforms from Codeship by Cloudbees, for an overview and comparison of Kubernetes platforms. 

Topics:
junit 5 ,junit ,java ,cdi ,tutorial ,software testing ,devops

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}