Micronaut testing with mock beans and clients

In real-world testing, you often need to isolate your code from external dependencies:

  • External APIs
  • Databases
  • Message brokers
  • Remote services

✅ This is where mocking becomes very important.
✅ Micronaut testing with mock beans and clients makes it easy to isolate and verify application logic without relying on external systems.

In our last post we saw Writing Integration Tests with Embedded Server

In this post, we’ll cover:

  • Why mocking is important
  • Mocking services
  • Mocking HTTP clients
  • Mocking beans for integration tests
  • Best practices
Micronaut testing with mock beans and clients

🏗 Why Mock in Tests?

ProblemSolution
Slow external callsMock responses
Unstable remote servicesIsolate tests
Complex DB setupFake repositories
Testing edge casesCustom mock behavior

🚀 Project Setup

Assume you have a basic Micronaut project already set up.

You need these dependencies in your Maven pom.xml:




    io.micronaut.test
    micronaut-test-junit5
    test



    org.mockito
    mockito-core
    test


🏫 Sample Use Case

Let’s say we have a WeatherService that calls an external weather API:


package com.kscodes.micronaut.services;

import jakarta.inject.Singleton;

@Singleton
public class WeatherService {

    public String getWeather(String city) {
        // Calls external API in real implementation
        return "Sunny in " + city;
    }
}

We want to mock this service while testing a controller that uses it.

🧪 Mocking Beans in Micronaut

Micronaut provides @MockBean annotation to replace real beans during tests.


✅ Example Controller


package com.kscodes.micronaut.controllers;

import com.kscodes.micronaut.services.WeatherService;
import io.micronaut.http.annotation.*;

@Controller("/weather")
public class WeatherController {

    private final WeatherService weatherService;

    public WeatherController(WeatherService weatherService) {
        this.weatherService = weatherService;
    }

    @Get("/{city}")
    public String getWeather(String city) {
        return weatherService.getWeather(city);
    }
}

✅ Integration Test with Mocked Bean


package com.kscodes.micronaut;

import com.kscodes.micronaut.services.WeatherService;
import io.micronaut.http.client.HttpClient;
import io.micronaut.http.client.annotation.Client;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import static org.junit.jupiter.api.Assertions.assertEquals;

@MicronautTest
class WeatherControllerTest {

    @Inject
    @Client("/")
    HttpClient httpClient;

    @Inject
    WeatherService weatherService;

    @Test
    void testWeatherWithMock() {
        Mockito.when(weatherService.getWeather("Mumbai")).thenReturn("Mocked Sunny in Mumbai");

        String response = httpClient.toBlocking().retrieve("/weather/Mumbai");
        assertEquals("Mocked Sunny in Mumbai", response);
    }
}

✅ Registering the MockBean

You must tell Micronaut to replace the original bean with a mock:


package com.kscodes.micronaut;

import com.kscodes.micronaut.services.WeatherService;
import io.micronaut.context.annotation.Factory;
import io.micronaut.test.annotation.MockBean;
import org.mockito.Mockito;

@Factory
public class MockFactory {

    @MockBean(WeatherService.class)
    WeatherService weatherService() {
        return Mockito.mock(WeatherService.class);
    }
}

✅ This ensures:

  • Micronaut replaces original WeatherService with mock.
  • The mock participates in dependency injection.
  • You can inject it directly and configure its behavior.

🔬 Mocking HTTP Clients (@Client)

Micronaut also allows you to mock HTTP clients used for external API calls.

✅ Sample Client


package com.kscodes.micronaut.clients;

import io.micronaut.http.annotation.Get;
import io.micronaut.http.client.annotation.Client;

@Client("https://api.weather.com")
public interface WeatherApiClient {

    @Get("/current?city={city}")
    String getWeather(String city);
}

✅ Service that uses the client


package com.kscodes.micronaut.services;

import com.kscodes.micronaut.clients.WeatherApiClient;
import jakarta.inject.Singleton;

@Singleton
public class WeatherService {

    private final WeatherApiClient weatherApiClient;

    public WeatherService(WeatherApiClient weatherApiClient) {
        this.weatherApiClient = weatherApiClient;
    }

    public String getWeather(String city) {
        return weatherApiClient.getWeather(city);
    }
}

✅ Test with Mocked HTTP Client


package com.kscodes.micronaut;

import com.kscodes.micronaut.clients.WeatherApiClient;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import static org.junit.jupiter.api.Assertions.assertEquals;

@MicronautTest
class WeatherApiClientTest {

    @Inject
    WeatherApiClient weatherApiClient;

    @Test
    void testClientMock() {
        Mockito.when(weatherApiClient.getWeather("Pune")).thenReturn("Mocked Rainy in Pune");
        String response = weatherApiClient.getWeather("Pune");
        assertEquals("Mocked Rainy in Pune", response);
    }
}

✅ Register MockBean for HTTP Client

package com.kscodes.micronaut;

import com.kscodes.micronaut.clients.WeatherApiClient;
import io.micronaut.context.annotation.Factory;
import io.micronaut.test.annotation.MockBean;
import org.mockito.Mockito;

@Factory
public class ClientMockFactory {

    @MockBean(WeatherApiClient.class)
    WeatherApiClient weatherApiClient() {
        return Mockito.mock(WeatherApiClient.class);
    }
}

⚠ Common Mistakes

ProblemCauseSolution
Real bean still usedMockBean not registeredUse @MockBean properly
NullPointerException on injectionIncorrect bean scopeEnsure proper injection
Mockito errorMixing static methodsUse Mockito for interface or class mocks

🧰 Best Practices for Micronaut testing with mock beans and clients

✅ Always separate unit tests and integration tests.
✅ Mock external systems — not your own service logic.
✅ Use Micronaut’s @MockBean instead of Mockito’s standalone @Mock.
✅ Avoid over-mocking — sometimes better to test full stack.
✅ Use application-test.yml for isolated config.

🌐 External References