I'm getting started with micronaut and I would like to understand the difference between testing the controller using local host and using an Embedded server
For example I have a simple controller
@Controller("/hello")
public class HelloController {
@Get("/test")
@Produces(MediaType.TEXT_PLAIN)
public String index() {
return "Hello World";
}
}
and the tested class
@MicronautTest
public class HelloControllerTest {
@Inject
@Client("/hello")
RxHttpClient helloClient;
@Test
public void testHello() {
HttpRequest<String> request = HttpRequest.GET("/test");
String body = helloClient.toBlocking().retrieve(request);
assertNotNull(body);
assertEquals("Hello World", body);
}
}
I got the logs:
14:32:54.382 [nioEventLoopGroup-1-3] DEBUG mylogger - Sending HTTP Request: GET /hello/test
14:32:54.382 [nioEventLoopGroup-1-3] DEBUG mylogger - Chosen Server: localhost(51995)
But then, in which cases we need an Embedded Server? why? where I can find documentation to understand it. I read the documentation from Micronaut but is not clear for me, what is actually occurring and why? like this example:
@Test
public void testIndex() throws Exception {
EmbeddedServer server = ApplicationContext.run(EmbeddedServer.class);
RxHttpClient client = server.getApplicationContext().createBean(RxHttpClient.class, server.getURL());
assertEquals(HttpStatus.OK, client.toBlocking().exchange("/hello/status").status());
server.stop();
}
In both cases, you are using
EmbeddedServerimplementation -NettyHttpServer. This is an abstraction that represents Micronaut server implementation (aNettyHttpServerin this case).The main difference is that
micronaut-testprovides components and annotations that make writing Micronaut HTTP unit tests much simpler. Beforemicronaut-test, you had to start up your application manually with:Then you had to prepare an HTTP client, for instance:
The
micronaut-testsimplifies it to adding@MicronautTestannotation over the test class, and the runner starts the embedded server and initializes all beans you can inject. Just like you do with injectingRxHttpClientin your example.The second thing worth mentioning is that the
@MicronautTestannotation also allows you to use@MockBeanannotation to override existing bean with some mock you can define at the test level. By default,@MicronautTestdoes not mock any beans, so the application that starts reflect 1:1 application's runtime environment. The same thing happens when you startEmbeddedServermanually - this is just a programmatic way of starting a regular Micronaut application.So the conclusion is quite simple - if you want to write less boilerplate code in your test classes, use
micronaut-testwith all its annotations to make your tests simpler. Without it, you will have to manually control all things (starting Micronaut application, retrieving beans from application context instead of using@Injectannotation, and so on.)Last but not least, here is the same test written without
micronaut-test:In this case, we can't use
@Injectannotation and the only way to create/inject beans is to useapplicationContextobject directly. (Keep in mind that in this case,RxHttpClientbean does not exist in the context and we have to create it - inmicronaut-testcase this bean is prepared for us upfront.)And here is the same test that uses
micronaut-testto make the test much simpler:Less boilerplate code, and the same effect. We could even
@Inject EmbeddedServer embeddedServerif would like to access it, but there is no need to do so.