Write and execute a JUnit test for a Java microservice based on MicroProfile and run both in the OpenLiberty development mode

This blog post has the focus on: how to develop a JUnit test for the Authors microservice from the Cloud Native Starter example and run both the Authors microservice and the JUnit test on OpenLiberty in the development mode.

That blog post hasn’t the objective to be a blueprint or a ‘how to guide’ for writing JUnit tests,  JUnit test organization, test strategy and so on. The objective is to get technically started along one concrete microservice example from the Cloud Native Starter project. Here is the GitHub project with the source code for this blog post.

The Authors microservice has one RESTful api endpoint called getAuthor. The endpoint provides one parameter for the Author name. The endpoint returns Author data in a JSON format.

Keep the end in mind: The gif shows a sample JUnit test execution for the Author microservice using OpenLiberty in the Visual Studio Code editor:

junit-on-openliberty-run-test

Note: As an alternative or in addition, you can also visit the OpenLiberty tutorial “MicroProfile or Jakarta EE application” to start with that topic.

Let’s start with: What do we need and how do we realize the implementation?

We need to ..

    •  invoke the REST endpoint of the Authors microservice with a REST Client.
    •  transform the JSON response of the REST endpoint to an Author data class
    •  handle different values to invoke the REST Endpoint parameter for the Author name to run tests with variations of the Author name.
    • compare the actual response value with an expected value and document the result.

And how to ..

    • setup a JUnit test for the development mode of the OpenLiberty server?
    • convert JSON Data from a String to an Author Java instance with JSON-B?
    • define a REST Client?
    • configure a parameterized JUnit test?
    • write the concrete parameterized JUnit test?
    • execute the JUnit test?
    • find the test results?

What are the tools and frameworks?

That are the Tools and frameworks of the sample project:


1. How to setup a JUnit test for the development mode of the OpenLiberty server?

To setup and run JUnit tests with the OpenLiberty server in the development mode, we have to provide a test folder in the src folder of our Java project. The image below shows the folders of my sample project.

open-liberty-junit-01-folderstructure

Content of the com.ibm.authors package for the Authors microservice

  • AuthorsApplication class represents the JAX-RS RESTful web application.
  • Author class represents the data structure we use for the Author.
  • GetAuthor class represents the REST API Endpoint.
  • HealthEndpoint class represents the support of readiness probes for Kubernetes.

Content of the authortests package for the JUnit test

  • AuthorJsonbAdapter class represents JSON-B adapter for a JSON-B mapping configuration.
  • AuthorTestClient class represents the REST Client of the Authors microservice.
  • Test_GetAuthors class represents the JUnit test which will be executed as the parameterized test run.

1.2 The pom.xml configuration for the JUnit and OpenLiberty

  • Dependencies

The junit-jupiter-api and the junit-jupiter-engine are the basics for the Unit tests. With the junit-jupiter-params depencency we can define later a parameterized test.

	<!-- JUnit Test --> 
	<dependency>
		<groupId>org.junit.jupiter</groupId>
		<artifactId>junit-jupiter-api</artifactId>
		<version>5.6.0</version>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.junit.jupiter</groupId>
		<artifactId>junit-jupiter-engine</artifactId>
		<version>5.6.0</version>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.junit.jupiter</groupId>
		<artifactId>junit-jupiter-params</artifactId>
		<version>5.6.0</version>
		<scope>test</scope>
	</dependency>
	<!-- JUnit Test -->
        <!-- JUNIT  -->
	<plugin>
		<artifactId>maven-surefire-plugin</artifactId>
		<version>2.22.2</version>
	</plugin>
	<plugin>
		<artifactId>maven-failsafe-plugin</artifactId>
		<version>2.22.2</version>
	</plugin>
	<!-- JUNIT -->
    <!-- Enable liberty-maven plugin -->
    <plugin>
        <groupId>io.openliberty.tools</groupId>
        <artifactId>liberty-maven-plugin</artifactId>
		<version>3.1</version>
		<!-- libertyMavenConfiguration -->
		<configuration>
                        <serverName>authorsDevJUnitServer</serverName>
			<configFile>liberty/server.xml</configFile>
                </configuration>
	        <!-- libertyMavenConfiguration -->
    </plugin>
    <!-- Enable liberty-maven-plugin -->

2. How to convert JSON Data from a String to an Author Java instance with JSON-B?

The response of our endpoint getAuthor is a text in a JSON format, but we want use that data in an instance of an Author class.

In JSON-B we define a JsonbAdapter which does the conversion from JSON to an Author class instance. Therefor we @Overridethe operations adaptToJsonandadaptFromJson. The operationadaptFromJson defines how to create an Author object from a JsonObject.

// Author data class
import com.ibm.authors.Author;

// JSON-binding
import javax.json.bind.adapter.JsonbAdapter;
import javax.json.JsonObject;
import javax.json.Json;

public class AuthorJsonbAdapter implements JsonbAdapter<Author, JsonObject> {
 
    ...

    @Override
    public Author adaptFromJson(final JsonObject jsonObject) throws Exception {
        final Author author = new Author();
        author.setBlog(jsonObject.getString("blog"));
        author.setName(jsonObject.getString("name"));
        author.setTwitter(jsonObject.getString("twitter"));
        return author;
    }
}

In the following code of the Test_GetAuthors class you see how to utilize the AuthorJsonbAdapter to create a new JSON-B configuration. That JSON-B configuration is used to create a JSON-B object. The JSON-B object contains the implemented operation fromJson and knows how to create an instance of an Author class.

final JsonbConfig config = new JsonbConfig().withAdapters(new AuthorJsonbAdapter());
final Jsonb jsonb = JsonbBuilder.create(config);    
final Author author_json = jsonb.fromJson(response, Author.class);

The pom.xml configuration for the JSON-B

We need to add following dependencies

<!-- JSONB --> 
<dependency>
   <groupId>org.eclipse</groupId>
   <artifactId>yasson</artifactId>
   <version>1.0</version>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>org.glassfish</groupId>
   <artifactId>javax.json</artifactId>
   <version>1.1</version>
   <scope>test</scope>
</dependency>		
<!-- JSONB -->

3. How to define a REST Client?

The following code shows the interface class AuthorTestClient. That class contains the REST Client interface definition for the REST Endpoint of the Authors microservice. With the usage of the MicroProfile annotation @RegisterRestClient a RESTful Client will be created, when the interface is used in the JUnit test.

The expected return value of getAuthors response type is defined as a String.

import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.QueryParam;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@Path("/getauthor")
@RegisterRestClient
public interface AuthorTestClient {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public String getAuthor(@QueryParam("name") String name);
}

4. How to configure the parameterized JUnit test?

The class Test_GetAuthors implements the JUnit test in the operation testGetAuthor. The test is defined as a ParameterizedTest and can be repeated with given values from a CsvSource.

  • ParameterizedTest

Here you see the annotation @ParameterizedTest and the configuration of name.
The name contains the count of the parameters, that test has two parameters and can be repeated.

@ParameterizedTest(name = "{index} => name=''{0},{1}''")

The concrete test implementation itself happens in the operation testGetAuthor. The operation contains the names for the parameters which were defined before. These parameters we will use in the test implementation.

public void testGetAuthor(
 final String authorName, 
 final String expectedResult)

For more details visit the JUnit documentation.

  • CsvSource

The annotation @CsvSource contains a comma separated list of values for the test execution. The values are in order to fit to parameters nameAuthor (Thomas) and expectedResult (Thomas Suedbroecker).

@CsvSource({"Thomas,Thomas Suedbroecker",
              "Niklas,Niklas Heidloff",
              "Michael,Michael Heinrich"
           })

For more details visit the JUnit documentation.


5. How to write the concrete parameterized JUnit test?

Step 1: Create a REST Client

To invoke our REST Endpoint getAuthor of the Authors microservice we use the RestClientBuilder from MicroProfile to create our REST Client.

We use our defined MicroProfile RestClient Interface AuthorTestClient.class and the RestClientBuilder will  create for us an object instance for the AuthorTestClient.

final AuthorTestClient authorClient = 
 RestClientBuilder.newBuilder()
                  .baseUri(baseURI)
                  .build(AuthorTestClient.class);

Step 2: Invoke the REST Client

Now we invoke the REST Client and we use our test parameter nameAuthor as input.

final String response = authorClient.getAuthor(nameAuthor);

Step 3: Convert the response to a Author data object

Once more the usage of JSON-B.

final JsonbConfig config = new JsonbConfig().withAdapters(new AuthorJsonbAdapter());
final Jsonb jsonb = JsonbBuilder.create(config);
final Author author_json = fromJson(response, Author.class);

Step 4: Compare the actual value of response with the expected value from the test parameter

To compare the actual and expected value we use the assertEquals from JUnit.

assertEquals(expectedResult, author_json.getName());

If a the values aren’t equal, assertEquals throws a AssertionFailedError exception and document the error in target/surefire-reports/TEST-authortests.Test_GetAuthors.txt file.

Here is an sample output of the TEST-authortests.Test_GetAuthors.txt file:

org.opentest4j.AssertionFailedError: 
expected: <Michael Heinrich> but was: <Niklas Heidloff>
at authortests.Test_GetAuthors.testGetAuthor(Test_GetAuthors.java:60)

For more details see in the JUnit documentation


6. How to execute the JUnit test?

With the usage of the liberty-maven-plugin we can start the OpenLiberty server in the development mode with following Maven command:

$ mvn liberty:dev

Then we just press return.

$ [INFO] Press the Enter key to run tests on demand.

7. How to find the test results?

The test results are stored in the target/surefire-reports/* folder.

open-liberty-junit-02-testresults

The gif shows, run the JUnit test a find the test results.

junit-on-openliberty-result


Here are additional useful blog posts, videos or manuals

MicroProfile RestClient

JUnit

Jsonb



I hope this was useful for you and let’s see what’s next?

Greetings,

Thomas

PS:  My GitHub project with the source code is here.

#JUnit, #JSON-B, #Java, #JAX-RS ,#VisualStudioCode,  #OpenLiberty, #MicroProfile

One thought on “Write and execute a JUnit test for a Java microservice based on MicroProfile and run both in the OpenLiberty development mode

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.