Micronaut Unit Testing ( Controllers and Services)

In this tutorial, we will learn how to perform Micronaut Unit testing for Controllers and Services. We will build a simple Student Management example using com.kscodes.micronaut package structure, and then create tests using JUnit 5 and Mockito.

Micronaut Unit Testing ( Controllers and Services)

As you have gone through Creating REST Endpoints with @Controller and @Get/@Post, lets see how Micronaut Unit testing for this is done.

Project Setup

We will create a simple Student Management system where we can:

  • Add a new student
  • Retrieve student details

Dependencies

In your pom.xml, make sure you have these dependencies:



    
    
        io.micronaut
        micronaut-inject
    

    
        io.micronaut
        micronaut-http-client
    

    
    
        org.junit.jupiter
        junit-jupiter-engine
        test
    

    
    
        org.mockito
        mockito-core
        test
    

    
    
        io.micronaut.test
        micronaut-test-junit5
        test
    


Create the Application Code

Student Model


package com.kscodes.micronaut.model;

public class Student {
    private String id;
    private String name;

    public Student(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

StudentService


package com.kscodes.micronaut.service;

import com.kscodes.micronaut.model.Student;

import jakarta.inject.Singleton;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@Singleton
public class StudentService {

    private final Map students = new HashMap<>();

    public void addStudent(Student student) {
        students.put(student.getId(), student);
    }

    public Optional getStudent(String id) {
        return Optional.ofNullable(students.get(id));
    }
}

StudentController


package com.kscodes.micronaut.controller;

import com.kscodes.micronaut.model.Student;
import com.kscodes.micronaut.service.StudentService;

import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.*;
import jakarta.inject.Inject;

import java.util.Optional;

@Controller("/students")
public class StudentController {

    @Inject
    private StudentService studentService;

    @Post
    public HttpResponse addStudent(@Body Student student) {
        studentService.addStudent(student);
        return HttpResponse.ok("Student added successfully");
    }

    @Get("/{id}")
    public HttpResponse getStudent(@PathVariable String id) {
        Optional student = studentService.getStudent(id);
        return student.map(HttpResponse::ok)
                      .orElseGet(() -> HttpResponse.notFound());
    }
}

Unit Testing the Service

Since StudentService is simple and has no external dependencies, we can write pure unit tests.


package com.kscodes.micronaut.service;

import com.kscodes.micronaut.model.Student;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class StudentServiceTest {

    @Test
    public void testAddAndGetStudent() {
        StudentService service = new StudentService();

        Student student = new Student("1", "John Doe");
        service.addStudent(student);

        Assertions.assertTrue(service.getStudent("1").isPresent());
        Assertions.assertEquals("John Doe", service.getStudent("1").get().getName());
    }

    @Test
    public void testGetStudentNotFound() {
        StudentService service = new StudentService();
        Assertions.assertFalse(service.getStudent("unknown").isPresent());
    }
}

Unit Testing the Controller

For the controller, we mock the StudentService dependency.


package com.kscodes.micronaut.controller;

import com.kscodes.micronaut.model.Student;
import com.kscodes.micronaut.service.StudentService;

import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import io.micronaut.http.HttpResponse;

import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class StudentControllerTest {

    @Mock
    StudentService studentService;

    @InjectMocks
    StudentController studentController;

    @Test
    public void testAddStudent() {
        Student student = new Student("1", "John Doe");
        HttpResponse response = studentController.addStudent(student);

        verify(studentService, times(1)).addStudent(student);
        assertEquals(200, response.getStatus().getCode());
        assertEquals("Student added successfully", response.body());
    }

    @Test
    public void testGetStudentFound() {
        Student student = new Student("1", "John Doe");
        when(studentService.getStudent("1")).thenReturn(Optional.of(student));

        HttpResponse response = studentController.getStudent("1");
        assertEquals(200, response.getStatus().getCode());
        assertEquals("John Doe", response.body().getName());
    }

    @Test
    public void testGetStudentNotFound() {
        when(studentService.getStudent("2")).thenReturn(Optional.empty());

        HttpResponse response = studentController.getStudent("2");
        assertEquals(404, response.getStatus().getCode());
    }
}

Summary

  • Use pure unit tests for services with no dependencies.
  • Use mocks (e.g. Mockito) to isolate controller tests from the service layer.
  • Micronaut makes testing simple with its dependency injection and fast startup time.

External References