Micronaut with Graal native image example.

As we have seen in the last couple of articles on how to create simple Micronauts application development and dockerizing it. In this article, we are gone exploring Helloworld Graal micronaut application.

Here is the definition from Wikipedia. If you are crossing this article that means you are familiar with either of the topic.

GraalVM is a Java VM and JDK based on HotSpot/OpenJDK, implemented in Java. It supports additional programming languages and execution modes, like an ahead-of-time compilation of Java applications for fast startup and low memory footprint. The first production-ready version, GraalVM 19.0, was released in May 2019.

Let us start coding and simultaneously enjoy the topic.

Create a micronaut application using CLI:

$ mn create-app helloworld-graal --features=graal-native-image

The default option is not available to add Graal support we have to use this option  — features=graal-native-image.

If you are using Java or Kotlin and IntelliJ IDEA make sure you have enabled annotation processing.

Now let us create one simple POJO class to hold Play name to make it simple.

import io.micronaut.core.annotation.Introspected;

@Introspected
public class Play{

    private String name;

    public Play(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

@Introspected annotation is used to generate BeanIntrospection metadata at compilation time. This information is using the render the POJO as JSON using Jackson without using reflection.

Now let us create the Singelton Service class and return play name randomly.

(Note:- The play names are Marathi Play names of famous Sri Pu la Deshpande)

import javax.inject.Singleton;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

@Singleton
public class PlayService {
// create list of plays
    private static final List<Play> PLAYS = Arrays.asList(
            new Play("Tujhe Ahe Tujpashi"),
            new Play("Sundar Mee Honar"),
            new Play("Tee Phularani"),
            new Play("Teen Paishacha Tamasha"),
            new Play("Ek Jhunj Varyashi")
    );
 // to choose random play from PLAYS list
    public Play randomPlay() {
        return PLAYS.get(new Random().nextInt(PLAYS.size()));
    }
}

Now we need a controller to serve the request of random play name from service class.

import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;

@Controller
public class PlayController {

    private final PlayService playService;

    public PlayController(PlayService playService) {
        this.playService = playService;
    }

    @Get("/randomplay")
    public Play randomPlay() {
        return playService.randomPlay();
    }
}

Created controller and injected service object using constructor injection and mapping of GET method using @Get(“/randomplay”).

Now our application is ready you can test by executing below command.

$ ./gradlew run

http://localhost:8080/randomplay

JSON output 

{

 name: “Tee Phularani”

}

Let us create a Graal native image.

Micronaut only supported in Java or Kotlin for graal native-image.

While creating a project we have added — features=graal-native-image this is adding three important features. 

  1. svm(Substrate VM) and graal dependencies in build.gradle.
compileOnly "org.graalvm.nativeimage:svm"
annotationProcessor "io.micronaut:micronaut-graal"

2. A Dockerfile which can be used to construct the native image executing docker-build.sh

3. A native-image.properties file in the resource directory.

Args = -H:IncludeResources=logback.xml|application.yml|bootstrap.yml \
       -H:Name=helloworld-graal \
       -H:Class=helloworld.graal.Application

This is very easy for developer to create a native image inside docker. Fire below two commands: 

$ ./gradlew assemble
$ ./docker-build.sh

Once image is ready we can create a container to verify our understanding. 

$ docker run -p 8080:8080 helloworld-graal

To test the application you can use curl with time:

$ time curl localhost:8080/randomplay

This is for now. You can check the time difference with native image executable and docker with a native image. 

Source code download or clone from github: https://github.com/maheshwarLigade/micronaut-examples/tree/master/helloworld-graal

Dockerise Micronaut application.

Micronauts is a java framework to develop a cloud-native microservices application easily and seamlessly. If you don’t know about Micronaut Please go through below two articles. 

In this article, we are exploring a micronaut framework and How to dockerize it. 

Let us create a small micronaut REST service application and try to dockerize it.

Micronaut provides a CLI option to create an application easily.

$ mn create-app helloworld

This will scaffold a new Gradle project. If you prefer Maven, add a --build maven parameter. If you want to create a new Groovy or Kotlin project, add a --lang parameter.

$ mn create-app --lang groovy helloworld-groovy
$ mn create-app --lang kotlin helloworld-kotlin

These options depend on you, which language are you comfortable with.

These options depend on you, which language are you comfortable with. 

Once the project is ready we can import that in your favorite editor. I am using IntelliJ.

We are using already created Hello world app, source code is available at below location you can clone

https://github.com/maheshwarLigade/micronaut-examples/tree/master/helloworld

By default, micronaut app can create Docker file for you and docker file you can locate on current directory of your project <appname>/Docker 

e.g helloworld/Docker

The Default content of Docker file:

FROM adoptopenjdk/openjdk13-openj9:jdk-13.0.2_8_openj9-0.18.0-alpine-slim
COPY build/libs/helloworld-*-all.jar helloworld.jar
EXPOSE 8080
CMD ["java", "-Dcom.sun.management.jmxremote", "-Xmx128m", "-XX:+IdleTuningGcOnIdle", "-Xtune:virtualized", "-jar", "helloworld.jar"]

If you are familiar with docker then fine if not you can explore below article to understand docker.

https://www.techwasti.com/demystify-docker-container-technology-9a8e1ec3968b/

Micronaut create docker file with alpine-slim 

and JDK image which is used here is unofficial.

This repo provides Unofficial AdoptOpenJDK Docker Images,

Reference:- https://hub.docker.com/r/adoptopenjdk/openjdk13-openj9

Thrid line to copy the generated jar(helloworld.jar) file and the expose default port as 8080. Last line to launch the jar file.

For this example, I am using Gradle as a build tool

$ cd helloworld
$ ./gradlew run

To test whether code is working fine or not. (curl http://localhost:8080/hello)

Now build a Docker image from the docker file for that fire below command. 

To run the application with IntelliJ IDEA, you need to enable annotation processing:

  1. open Settings → Build → Execution → Deployment → Compiler →Annotation Processors
  2. Set the checkbox Enable annotation processing

As we know micronaut CLI generates a Dockerfile by default, making it easy to package your application for a container environment such as Kubernetes.

$ docker build . -t hello-world-ex

Fire above command to create a docker image. -t 1.0.0 indicates the tag for this image. Now our image is ready to make a container from its fire below command. 

$ docker run --rm -p 8080:8080 hello-world-ex

As we have exposed 8080 port in docker file. We are doing port mapping to an external system.

to verify the docker image fire below command.

$ curl http://localhost:8080/hello

In this article, we have seen dockerizing micronaut apps. We have created helloworld application and created a docker image using the existing Docker file. You can edit the docker file and optimize it as per your requirement. 

Spring Boot Firebase CRUD

In this article, we show How to build a CRUD application using Firebase and Spring boot.

Create a Firebase project in the Firebase console:

https://console.firebase.google.com/

Hit the https://console.firebase.google.com and sign up for an account.

Click the “Add Project” button from the project overview page.

Type “Firebase DB for Spring Boot” in the “Project name” field.

Click the “CREATE PROJECT” button.

Now we have created a project on Firebase, now let us add firebase to our spring boot app.

Add Firebase to your web app:

You can find your Realtime Database URL in the Database tab (DEVELOP → Database → Realtime Database → Start in test Mode ) in the Firebase console. It will be in the form of https://<databaseName>.firebaseio.com.

Create Firebase in test mode this is not useful for Prod development but for our this article we will use it in test mode which is available publicly. 

Your Database URL should look like this https://<Projectname XYZ>.firebaseio.com/

Our data is ready but still, we need a service account 

Go and click on Project settings → Service Accounts → Choose Language as Java. to copy code snippet

and Download JSON file as well by clicking on “Generate new private key”

We will also grab the admin SDK configuration snippet for java.

Then go to https://start.spring.io/ and create a project, Once the project added then open the pom.xml file and add below dependency.

<dependency>
    <groupId>com.google.firebase</groupId>
    <artifactId>firebase-admin</artifactId>
    <version>6.11.0</version>
 </dependency>

Now everything is ready to Let us initialize Firebase Database.

import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.FileInputStream;

@Service
public class FBInitialize {

    @PostConstruct
    public void initialize() {
        try {
            FileInputStream serviceAccount =
                    new FileInputStream("./serviceaccount.json");

            FirebaseOptions options = new FirebaseOptions.Builder()
                    .setCredentials(GoogleCredentials.fromStream(serviceAccount))
                    .setDatabaseUrl("https://chatapp-e6e15.firebaseio.com")
                    .build();

            FirebaseApp.initializeApp(options);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

I am using the existing Firebase Database.

@Service and @PostConstruct these are the two annotations from Spring Boot. 

First-line reads the configurations from the JSON file and then initializes the connection for the specified database. 

Now firebase connection is initialized then let us create CRUD operations.

Create a POJO class as a Patient

public class Patient {

    private String name;

    private int age;

    private String city;


    public Patient(String name, int age, String city) {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }
}

Create Service class

import com.google.api.core.ApiFuture;
import com.google.cloud.firestore.DocumentReference;
import com.google.cloud.firestore.DocumentSnapshot;
import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.WriteResult;
import com.google.firebase.cloud.FirestoreClient;
import org.springframework.stereotype.Service;

import java.util.concurrent.ExecutionException;

//CRUD operations
@Service
public class PatientService {

    public static final String COL_NAME="users";

    public String savePatientDetails(Patient patient) throws InterruptedException, ExecutionException {
        Firestore dbFirestore = FirestoreClient.getFirestore();
        ApiFuture<WriteResult> collectionsApiFuture = dbFirestore.collection(COL_NAME).document(patient.getName()).set(patient);
        return collectionsApiFuture.get().getUpdateTime().toString();
    }

    public Patient getPatientDetails(String name) throws InterruptedException, ExecutionException {
        Firestore dbFirestore = FirestoreClient.getFirestore();
        DocumentReference documentReference = dbFirestore.collection(COL_NAME).document(name);
        ApiFuture<DocumentSnapshot> future = documentReference.get();

        DocumentSnapshot document = future.get();

        Patient patient = null;

        if(document.exists()) {
            patient = document.toObject(Patient.class);
            return patient;
        }else {
            return null;
        }
    }

    public String updatePatientDetails(Patient person) throws InterruptedException, ExecutionException {
        Firestore dbFirestore = FirestoreClient.getFirestore();
        ApiFuture<WriteResult> collectionsApiFuture = dbFirestore.collection(COL_NAME).document(person.getName()).set(person);
        return collectionsApiFuture.get().getUpdateTime().toString();
    }

    public String deletePatient(String name) {
        Firestore dbFirestore = FirestoreClient.getFirestore();
        ApiFuture<WriteResult> writeResult = dbFirestore.collection(COL_NAME).document(name).delete();
        return "Document with Patient ID "+name+" has been deleted";
    }

}

Now we are ready with CRUD operation let us develop the REST Controller which will help us in interaction with this service layer.

Note:- You have to enable Cloud FireStore API.

Now we just need to create Controller which can handle REST request.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.concurrent.ExecutionException;

@RestController
public class PatientController {

    @Autowired
    PatientService patientService;

    @GetMapping("/getPatientDetails")
    public Patient getPatient(@RequestParam String name ) throws InterruptedException, ExecutionException{
        return patientService.getPatientDetails(name);
    }

    @PostMapping("/createPatient")
    public String createPatient(@RequestBody Patient patient ) throws InterruptedException, ExecutionException {
        return patientService.savePatientDetails(patient);
    }

    @PutMapping("/updatePatient")
    public String updatePatient(@RequestBody Patient patient  ) throws InterruptedException, ExecutionException {
        return patientService.updatePatientDetails(patient);
    }

    @DeleteMapping("/deletePatient")
    public String deletePatient(@RequestParam String name){
        return patientService.deletePatient(name);
    }
}

Now coding is done try by yourself and let’s know.

Installation of Micronaut on Mac(OSX) & Linux.

Micronaut is a full framework to develop cloud native microservice architecture based application using java, kotlin or Groovy.

Let us check the steps required to install micronaut on OSx.

Simple and effortless start on Mac OSX, Linux, you can use SDKMAN! (The Software Development Kit Manager) to download and configure any Micronaut version of your choice.

INSTALLING WITH SDKMAN:

This tool makes installing of a Micronaut on any Unix based platform such as Linux, OSx.

Open a terminal and install SDKMAN,

$  curl -s https://get.sdkman.io | bash

Follow the on-screen instructions to complete installation.

Then fire below command after installation of SDKMAN to configure SDKMAN.

 $ source "$HOME/.sdkman/bin/sdkman-init.sh"

Once above two steps are in align then go and setup micrnaut using SDKMAN,

$ sdk install micronaut

After installation is complete it can be validated with below command.

$ mn --version
installation and validation of micronaut

this is the simple steps with SDKMAN.

INSTALLING WITH HomeBrew:

Before installation using homebrew you should update homebrew version

$ brew update

In order to install Micronaut, run following command:

$ brew install micronaut

After installation is complete it can be validated with below command.

$ mn --version

Installing with MacPorts:

Before installing it is recommended to sync the latest Portfiles, So that there shouldn’t be any issue,

$ sudo port sync

To install Micronaut, run following command

$ sudo port install micronaut

After installation is complete it can be validated with below command.

$ mn --version

Above are they three different way we can setup micronaut framework on MacOS and linux based OS.

Micronaut java full stack Microservice Framework!!

Micronaut is a modern, JVM-based, full-stack microservices framework designed for building modular, easily testable microservice applications.

Micronaut is the latest framework designed to make creating microservices quick and easy.

Micronaut is a JVM-based framework for building lightweight, modular applications. Developed by OCI, the same company that created Grails. Micronaut is developed by the creators of the Grails framework and takes inspiration from lessons learned over the years building real-world applications from monoliths to microservices using Spring, Spring Boot, and Grails.

Micronaut supports Java, Groovy or Kotlin.

Features of Micronaut:-

One of the most exciting features of Micronaut is its compile-time dependency injection mechanism. If you know the spring-boot mostly using reflection API and proxies which is always at run time and that causing the spring boot application needs a more startup time as compared to Node application. 

  1. First-class support for reactive HTTP clients and servers based on Netty.
  2. An efficient compile time dependency injection container. 
  3. Minimal startup time and lower memory usage.
  4. Cloud-native features to boost developer productivity.
  5. Very minimal learning curve because Micronaut code looks very similar to Spring Boot with Spring Cloud.

What’s wrong with Spring Boot?

Disclaimer 

There is nothing wrong with spring boot. I am a very big fan of spring projects including spring, spring Boot, Spring Data, etc. Spring Boot is a good and very elegant solution and it makes developer job easier than anything, just add one dependency and magic will happen for you. 

When spring is providing things on your fingertip that means spring is doing so many things under the hood for you. Spring does reflection, proxy classes and injection and many more and for this, you have to pay the cost because spring does things at runtime. You have pay in terms of memory, CPU cycles and application bootstrap time.

Micronaut addressed some of these problems using ATC (Ahead of time compilation), GraalVM. Micronaut does major things at compile time that reduces memory footprint and CPU utilization this leads to reduce in application bootstrap time. Currently, spring is not supporting GraalVM and Micronaut is supporting this is also a big difference. 

GraalVM is basically a high-performance polyglot VM. GraalVM is a universal virtual machine for running applications written in JavaScript, Python, Ruby, R, JVM-based languages like Java, Scala, Groovy, Kotlin, Clojure, and LLVM-based languages such as C and C++.

Now we know what is and why Micronaut and a couple of features. Let us setup Micronaut and we will create one simple Hello world application. 

Setup Micronaut?

To install or setup micronaut is a very easy task. Go to this page https://micronaut.io/download.html

Either you can download binary, or use SDKMAN to setup micronaut on your favorite OS.

Using SDKMAN

Simply open a new terminal and start:

$ curl -s https://get.sdkman.io | bash

$ source “$HOME/.sdkman/bin/sdkman-init.sh”

$ sdk install micronaut

$ mn — version

Now installation is done let us create simple Hello world application

mn create-app hello-world

By Default Micronaut uses Gradle as a build tool you can also specify maven as well.

mn create-app hello-world --build maven

Using Homebrew

Before installing make sure you have the latest Homebrew installed.

$ brew update

$ brew install micronaut

Using Binary on windows

  1. Download the latest binary from
  2. Extract the binary to appropriate location
  3. Create an environment variable MICRONAUT_HOME which points to the installation directory
  4. Update the PATH environment variable, append %MICRONAUT_HOME%\bin

Now enjoy the coding.

Let us have HelloWorld controller 

import io.micronaut.http.MediaType; 
import io.micronaut.http.annotation.Controller; 
import io.micronaut.http.annotation.Get; 
@Controller("/hello")  
public class HelloController {  
    
@Get(produces = MediaType.TEXT_PLAIN)      
public String index() { 
        
return "Hello World";     
 
} 
}

Now enjoy the output:

$ curl http://localhost:8080/hello 

> Hello World

Conclusion:-

Spring boot and micronaut both have some pros and cons. As per my understanding if you are developing a new greenfield application start with micronaut but don’t rewrite existing application of spring boot to micronaut unless and until you are facing some serious performance issues. If you are migrating from monolith to cloud-native microservice then micronaut is the good option. Please let us know your thoughts on this.

Reference link:

This is the performance comparison between spring boot and micronaut.

https://docs.micronaut.io/latest/guide/index.html

JUnit5: Parameterized Tests

As we studied in Junit5 in part1 and part2. Junit5 is very impressive in the extension model and architectural style, also the Junit5 Assumptions. The another best aspect about junit5 is compatibility with a lambda expression. In this section let us start looking for Junit5 parameterized tests.

The term parameter is often used to refer to the variable as found in the function definition, while argument refers to the actual input passed.

Maven Dependency:

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.4.2</version>
<scope>test</scope>
</dependency>

Gradle Dependency:

testCompile("org.junit.jupiter:junit-jupiter-params:5.4.2")

The basic difference while annotating the method instead of start by declaring a test method on @ParameterizedTest instead of @Test for a parameterised test. There are few scenarios where we want to pass values dynamically as method argument and a unit test that for this type of a scenario parameterized test cases are useful.

It looks below code is incomplete. From where this word value will come. how would JUnit know which arguments the parameter word should take? And indeed, Jupiter engine does not execute the test and instead throw a PreconditionViolationException.

@ParameterizedTest
void parameterizedTest(String word) {
 assertNotNull(word);
}
Configuration error: You must provide at least
one argument for this @ParameterizedTest

Let us start correcting the above exception.

@ParameterizedTest
@ValueSource(strings = {"JUnit5 ParamTest" , "Welcome"})
void withValueSource(String word) {
 assertNotNull(word);
}

Now above code will successfully get executed. This is just a simple use case but in real life project, you need more tools for that purpose you should know in detail of @ValueSource annotation.

ValueSource:

@ValueSource annotation is to provide a source of argument to the parameterized test method. The source can be anything like single value, an array of values, null source, CSV file, etc. As we have seen in the above example @ValueSource annotation, we can pass an array of literal values to the test method.

public class Strings {
     public static boolean isEmptyString(String str) {
         return str == null || str.trim().isEmpty();
     }
 }
// Test case for the above method could be 
@ParameterizedTest
@ValueSource(strings = {"", "  ","Non Empty"})
 void isEmptyStringReturnTrueForNullOrBlankStrings(String str) {
     assertTrue(Strings.isEmptyString(str));
 }

Limitations of value sources:

1. It only support the following data types.

2. We can pass only one argument to the test method each time.

3. We can not pass null as a argument to the test method.

  • short (with the shorts attribute)
  • byte (with the bytes attribute)
  • int (with the ints attribute)
  • long  (with the longs attribute)
  • float (with the floats attribute)
  • double (with the doubles attribute)
  • char (with the chars attribute)
  • java.lang.String (with the strings attribute)
  • java.lang.Class (with the classes attribute)

@NullSource and @EmptySource:

We can pass a single null value to a parameterized test method using @NullSource and its not for the primitive data types.

@EmptySource passes a single empty argument and you can use empty source for collection types and for array too.

In order to pass both null and empty values, we can use the composed @NullAndEmptySource annotation

@ParameterizedTest
@NullAndEmptySource
@ValueSource(strings = {” “, “\t”, “\n”})
void isEmptyStringReturnTrueForAllTypesOfBlankStrings(String input) {
assertTrue(Strings.isEmptyString(input));
}

EnumSource:

The name implies its self, if we want to test different values from an enumeration, we can use @EnumSource.

@ParameterizedTest
@EnumSource(WeekDay.class)
void getValueForADay_IsAlwaysBetweenOneAndSeven(WeekDay day) {
int dayNumber = day.getValue();
assertTrue(dayNumber >= 1 && dayNumber <= 7);
}

We can filter out a few days by using the names attribute of enum. @EnumSource annotation has option to select enum constant mode, you can either include and exclude too using EnumSource.Mode.EXCLUDE.

We can pass a string literal and regular expression both to the names attribute

Reference Document

CsvSource:

We need argument sources capable of passing multiple arguments. As we know @ValueSource and @EnumSource are only allowing one argument each time. In real life project we want to read row input values manipulate those and unit test those for that purpose @CsvSource

@ParameterizedTest
@CsvSource(value = {“juniT:junit”, “MaN:man”, “Java:java”}, delimiter = ‘:’)
void toLowerCaseValue(String input, String expected) {
String actualValue = input.toLowerCase();
assertEquals(expected, actualValue);
}

In the above example you have key value pair with colon as a delimiter, we can also pass CSV file as a resource argument too:

//CSV file
input,expected
Ram,RAM
tYpE,TYPE
Java,JAVA
koTliN,KOTLIN

@ParameterizedTest
@CsvFileSource(resources = “/testdata.csv”, numLinesToSkip = 1)
void toUpperCaseValueCSVFile(String input, String expected) {
String actualValue = input.toUpperCase();
assertEquals(expected, actualValue);
}

resources attribute represents the CSV file resources on the classpath and we can pass multiple CSV files too. Let us take few more examples

@ParameterizedTest
@CsvSource({
“2019-09-21, 2018-09-21”,
“null, 2018-08-15”,
“2017-04-01, null”
})
void shouldCreateValidDateRange(LocalDate startDate, LocalDate endDate) {
new DateRange(startDate, endDate);
}

@ParameterizedTest
@CsvSource({
“2019-09-21, 2017-09-21”,
“null, null”
})
void shouldNotCreateInvalidDateRange(LocalDate startDate, LocalDate endDate) {
assertThrows(IllegalArgumentException.class, () -> new DateRange(startDate, endDate));
}

When you are executing above programming you will end up getting exception.

org.junit.jupiter.api.extension.ParameterResolutionException: Error converting parameter at index 0: Failed to convert String “null” to type java.time.LocalDate

The null value isn’t accepted in @ValueSource or@CsvSource.

Method Source:

The @ValueSource and @EnumSource and pretty simple and has one limitation they won’t support complex types. MethodSource allows providing complex argument source. MehtodSource annotation takes the name of a method as an argument needs to match an existing method that returns Steam type.

@ParameterizedTest
@MethodSource(“wordsWithLength”)
void withMethodSource(String word, int length) { }

private static Stream wordsWithLength() {
return Stream.of(
Arguments.of(“JavaTesting”, 10),
Arguments.of(“JUnit 5”, 7));
}

When we won’t provide a name for the @MethodSource, JUnit will search for a source method with the same name as the parameterized test  method.

@ParameterizedTest
@MethodSource(“wordsWithLength”)
void wordsWithLength(String word, int length) { }

Custom Argument Provider:

As of now, we have covered inbuilt argument provider but in few scenarios, this doesn’t work for you then Junit provides custom argument provider. You can create your own source, argument provider. To achieve this we have to implement an interface called ArgumentsProvider.

public interface ArgumentsProvider {
Stream<? extends Arguments> provideArguments(
    ContainerExtensionContext context) throws Exception;
}

Example:

For this, we have just test with a custom empty String provider.

class EmptyStringsArgumentProvider implements ArgumentsProvider {

@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
    return Stream.of( 
      Arguments.of(""), 
      Arguments.of("   "),
      Arguments.of((String) null) 
    );
}
}

We can use this custom argument a provider using @ArgumentSource annotation.

@ParameterizedTest
@ArgumentsSource(EmptyStringsArgumentProvider.class)
void isEmptyStringsArgProvider(String input) {
assertTrue(Strings.isBlank(input));
}

Summery:

As part of this article, we have discussed Parameterised test cases and argument provider in bits and pieces and some level of custom argument provider using ArgumentsProvider interface and @ArgumentsSource.

There are different source provider from primitive to CSV and MethodSource provider. This is for now.

Junit5 Assumptions

Assumptions are used to run tests only if certain conditions are met. This is typically used for external conditions that are required for the test to execute properly, but which are not directly related to whatever is being unit tested.

If the assumeTrue() condition is true, then run the test, else aborting the test.

If the assumeFalse() condition is false, then run the test, else aborting the test.

The assumingThat() is much more flexible, it allows part of the code to run as a conditional test.

When the assumption is false, a TestAbortedException is thrown and the test is aborting execution.

@Test
void trueAssumption() {
    assumeTrue(6 > 2);
    assertEquals(6 + 2, 8);
}

@Test
void falseAssumption() {
    assumeFalse(4 < 1);
    assertEquals(4 + 2, 6);
}

@Test
void assumptionThat() {
    String str = "a simple string";
    assumingThat(
        str.equals("a simple string"),
        () -> assertEquals(3 + 2, 1)
    );
}

https://www.techwasti.com/junit5-tutorial-part-1/
https://www.techwasti.com/junit5-part2/

Junit5 tutorial: Part2

Before exploring this part, please read first part 1 is here.

Junit5 for beginners. In this tutorial let us make our hands dirty and have practical experience. If you are using Maven or Gradle for either of the build tool you can use dependency.

Maven dependency for Junit 5.0:

Add below dependency in pom.xml.

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

Junit 5.0 with Gradle:

Add below dependency in build.gradle file. We can start by supplying the unit test platform to the build tool. Now we have specified test platform as Junit.

test {useJUnitPlatform()}

Now after the above steps, we need to provide Junit5 dependencies here is the difference between Junit4 and junit5. As we have discussed in previous article Junit5 is modular so we have three different modules and each one has a different purpose.

dependencies 
{
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
}

In JUnit 5, though, the API is separated from the runtime, meaning two dependencies have to provide testImplementation and timeRuntimeOnly respectively.

The API is manifest with junit-jupiter-api. The runtime is junit-jupiter-engine for JUnit 5, and junit-vintage-engine for JUnit 3 or 4.

1. JUnit Jupiter:

In the first article, we have explored the difference between Junit4 and Juni5. There are new annotations introduced as part of this module. JUnit 5 new annotations in comparison to JUnit 4 are:

@Tag — Mark tags to test method or test classes for filtering tests.

@ExtendWith —Register custom extensions.

@Nested — Used to create nested test classes.

@TestFactory — Mark or denotes a method is a test factory for dynamic tests.

@BeforeEach — The method annotated with this annotation will be run before each test method in the test class. (Similar to Junit4 @Before )

@AfterEach — The method annotated with this annotation will be executed after each test method. (Similar to Junit4 @After )

@BeforeAll — The method annotated with this annotation will be executed before all test methods in the current class. (Similar to Junit4 @BeforeClass )

@AfterAll — The method annotated with this annotation will be executed after all test methods in the current class. (Similar to Junit4 @AfterClass )

@Disable — This is used to disable a test class or method (Similar to Junit4 @Ignore)

@DisplayName — This annotation defines a custom display name for a test class or a test method.

2. JUnit Vintage:

As part of this module, there is no new annotation has introduced but the purpose of this module is to supports running JUnit 3 and JUnit 4 based tests on the JUnit 5 platform.

Let us deep dive and do some coding:

@DisplayName and @Disabled:

As you can capture from the below code snipept you can DisplayName I have just given two flavors of one method. This way you can provide your own custom display name to identify test easily.

@DisplayName("Happy Scenario")
@Test
void testSingleSuccessTest() 
{
System.out.println("Happy Scenario");
}

@Test
@DisplayName("Failure scenario")
void testFailScenario() {
System.out.println("Failure scenario")
}

To disable test cases which implementation not yet completed or some other reason to skip that

@Test
@Disabled("Under constructution")
void testSomething() {
}

@BeforeAll and @BeforeEach :

BeforeAll is like a setup method this will get invoked once before all test methods in this test class and BeforeEach get invoked before each test method in this class.

@BeforeAll annotation must be, static and it’s run once before any test method is run.

@BeforeAll
static void setup() {
System.out.println("@BeforeAll: get executes once before all test methods in this class");
System.out.println("This is like setup for tests methods");
}

@BeforeEach
void init() {
System.out.println("@BeforeEach: get executes before each test method in this class");
System.out.println("initialisation before each test method");
}

@AfterEach and @AfterAll:

AfterEach gets invoked after each test method in this class and AfterAll get invoked after all test cases get invoked. Afterall like finalization task.

@AfterAll annotation must be, static and it’s run once after all test methods have been run.

@AfterEach
void tearDown() {
System.out.println("@AfterEach: get executed after each test method.");
}
@AfterAllstatic void finish() {
System.out.println("@AfterAll: get executed after all test methods.");
}

Assertions and Assumptions:

Assertions and assumptions are the base of unit testing. Junit5 taking full advantage of Java8 features such as lambda to make assertions simple and effective.

Assertions:

Junit5 assertions are part of a org.junit.jupiter.api.Assertions API and improvision have significantly as Java 8 is the base of Junit5 you can leverage all the features of Java8 primarily lambada expression. Assertions help in validating the expected output with the actual output of a test case.

@Test
void testLambdaExpression() {
assertTrue(Stream.of(4, 5, 9)
.stream()
.mapToInt(i -> i)
.sum() > 18, () -> "Sum should be greater than 18");
}

As you are aware of using lambda expression because of lambda expression

All JUnit Jupiter assertions are static methods

@Test
void testCase()
{
//Pass
Assertions.assertNotEquals(3, Calculator.add(2, 2));

//Fail
Assertions.assertNotEquals(4, Calculator.add(2, 2), "Calculator.add(2, 2) test failed");

//Fail
Supplier<String> messageSupplier = ()-> "Calculator.add(2, 2) test failed";
Assertions.assertNotEquals(4, Calculator.add(2, 2), messageSupplier);
}

With assertAll()which will report any failed assertions within the group with a MultipleFailuresError

Junit5 tutorial: Part-1

Junit5 tutorials for beginner.

Junit is the Java’s most popular unit testing library, recently has released a new version 5. JUnit 5 is a combination of several modules from three different sub-projects. 

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

JUnit is an open-source Unit Testing Framework for JAVA. It is useful for Java Developers to write and run unit tests. Erich Gamma and Kent Beck initially develop it.

JUnit 5 is an evolution of JUnit 4, and did some further improves the testing experience. As we are aware Junit5 is the major version release and its aims to adapt java 8 styles of coding and to be more robust and flexible than the previous releases. 

JUnit 5 was to completely rewrite JUnit 4

Advantages:- Below are the few advancements in this version over older once.

  1. The entire framework was contained in a single jar library.
  2. In JUnit 5, we get more granularity and can import only what is necessary.
  3. JUnit 5 makes good use of Java 8 styles of programming and features.
  4. JUnit 5 allows multiple runners to work simultaneously.
  5. The best thing about Junit5 is backward Compatibility for JUnit 4.

Note:- JUnit 5 requires Java 8 (or higher) at runtime.

Moving from Junit 4 to Junit5:-

In this section let us explore the motivation behind the Junit5.

  1. Junit4 was developed a decade ago, now context has bit changed and programming style too.
  2. Junit4 is not compatible with JDK8 and its new functional programming paradigm.
  3. Junit4 is not modular. A single jar is a dependency for everything. 
  4. Test discovery and execution are tightly coupled in Junit4.
  5. The most important thing nowadays developer not only want unit testing but also they want integration testing and system testing.

These are few reasons to rewrite junit5 from scratch using java8 and introduced some new features.

You can still execute Junit3 and Junit4 unit test cases using Vintage module in Junit5.

Architecture:-

Junit5 is modular architecture and the main three components are Platform, Jupiter and vintage.

Let us understand above this three module.

  1. Platform:- Platform, which serves as a foundation for launching testing frameworks on the JVM. It also provides an API to launch tests from either the console, IDEs, or build tools.
  2. Jupiter:- Jupiter is the combination of the new programming model and extension model for writing tests and extensions in JUnit 5. The name has been chosen from the 5th planet of our Solar System, which is also the largest one.
  3. Vintage:- Vintage in general something from the past. Vintage provides a test engine for running JUnit 3 and JUnit 4 based tests on the platform, ensuring the necessary backward compatibility.

As part of this tutorial, we are able to understand what is new Junit5 and what is it. In the next tutorial, we will explore more and we will take some examples. 

Amazon Corretto!! Another JDK

Amazon Corretto!! Another JDK

For more stories.

No-cost, multiplatform, production-ready distribution of OpenJDK.

Amazon Corretto, a No-Cost Distribution of OpenJDK. From title and Subtitle, you got an idea that this is the openJDK distribution from Amazon.

It’s really great news for Java developers. Amazon has released blog post with below title that makes sense for each one why not this distribution.

Amazon Corretto, a No-Cost Distribution of OpenJDK with Long-Term Support.

“Amazon has a long and deep history with Java. I’m thrilled to see the work of our internal mission-critical Java team being made available to the rest of the world” — James Gosling

Amazon corretto is a no cost, multiplatform, production-ready open JDK distribution. It comes with long-term support including performance enhancements and security fixes. Amazon using corretto internally using in production on thousands of services. This means it is fully tested.

Just FYI Corretto is an Italian word, in English meaning is ” Correct “.

Corretto is certified as compatible with the Java SE standard and is used internally at Amazon for many production services. With Corretto, you can develop and run Java applications on operating systems such as Amazon Linux 2, Windows, and macOS. In response to AWS Linux’s long-term support for Java, AWS recently released the free OpenJDK Amazon Corretto to ensure that cloud users can get stable support. Secure the operation of Java workloads. To ensure compatibility, Arun Gupta, AWS’s chief open source technologist, said that every time Amazon Corretto is released, the development team will implement the TCK (Technology Compatibility Kit) to ensure that the component is compatible with the Java SE platform.

@arungupta said that the workload of Amazon’s internal formal environment also relies heavily on Amazon Corretto’s JDK to meet high performance and large-scale demand. Amazon Corretto can support multiple heterogeneous environments, including the cloud, local data centers, and user development environments. In addition, to expand the scope of application of developers, the platform supported by Amazon Corretto at this stage includes Amazon Linux 2, Windows, macOS and Docker image files. The official version of Amazon Corretto is expected to be released in the first quarter of 2019, and will be compatible with Ubuntu and Red Hat Enterprise Linux.

The JDK is now available for free download by open users, and AWS also promises that Amazon Corretto version 8 free security updates will be available at least until June 2023, while Amazon Corretto version 11 free updates will continue until 2024. August.

This is just a developer preview release if you are a developer go ahead and make your hands dirty with this one.

Benefits:-

  1. Backed by Amazon.
  2. Production ready
  3. Multiplatform Support: Linux, Windows, Osx & Docker container too.
  4. No Cost.

You can find the source code for Corretto at github.com/corretto.

Official Documentation and download preview link

How to install on mac os:

Mac operating system version 10.10 or later. You must have administrator privileges to install and uninstall Amazon Corretto 8.

  1. Download amazon-corretto-jdk-8u192-macosx-x64.pkg.
  2. Double-click the downloaded file to start the installation wizard. Follow the steps in the wizard.
  3. Once the wizard completes, the Corretto 8 Preview will be installed in /Library/Java/JavaVirtualMachines/.

To get the complete installation path, run the following command in a terminal

/usr/libexec/java_home — verbose

4. Set the JAVA_HOME variable.

export JAVA_HOME=/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home

And enjoy the coding.

For Docker:

Build a docker image with Amazon corretto 8.

docker build -t amazon-corretto-jdk-8 github.com/corretto/corretto-8-docker

Your docker image is ready and a name is amazon-corretto-jdk-8. Run it using below command

docker run -it amazon-corretto-jdk-8

If you want to develop java application and want to use amazon corretto as a parent Image then follow below script.

let us create Hello world java app with amazon corretto.

  1. Create a Dockerfile with the following content.

FROM amazon-corretto-8 RUN

echo $’ \

public class Hello { \

public static void main(String[] args) { \

System.out.println(“Welcome to Amazon Corretto 8!”);

\ }

\ }’ > Hello.java

RUN javac Hello.java

CMD [“java”, “Hello”]

2. Build the image.

docker build -t hello-app .

3. Run the image

docker run hello-app

4. Output

Welcome to Amazon Corretto 8!

If you enjoyed this article, please don’t forget to Clap.

For more stories.

Lets connect on Stackoverflow , LinkedIn , Facebook& Twitter.