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

π Why Mock in Tests?
Problem | Solution |
---|---|
Slow external calls | Mock responses |
Unstable remote services | Isolate tests |
Complex DB setup | Fake repositories |
Testing edge cases | Custom mock behavior |
π Project Setup
Assume you have a basic Micronaut project already set up.
You need these dependencies in your Maven pom.xml
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<dependency> <groupId>io.micronaut.test</groupId> <artifactId>micronaut-test-junit5</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <scope>test</scope> </dependency> |
π« Sample Use Case
Letβs say we have a WeatherService
that calls an external weather API:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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
Problem | Cause | Solution |
---|---|---|
Real bean still used | MockBean not registered | Use @MockBean properly |
NullPointerException on injection | Incorrect bean scope | Ensure proper injection |
Mockito error | Mixing static methods | Use 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.