Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document how to get an HttpClient when singletons are eagerly initialised #716

Merged
merged 6 commits into from
Feb 16, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions src/main/docs/guide/introduction.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,39 @@ This is achieved through a set of annotations:

These annotations use internal Micronaut features and do not mock any part of Micronaut itself. When you run a test within `@MicronautTest` it is running your real application.

In some tests you may need a reference to the `ApplicationContext` and/or the `EmbeddedServer` (for example, to create an instance of an `HttpClient`). Rather than defining these as properties of the test (such as a `@Shared` property in Spock), when using `@MicronautTest` you can reference the server/context that was started up for you, and inject them directly in your test.
In some tests you may need a reference to the `ApplicationContext` and/or the `EmbeddedServer` (for example, to create an instance of an `HttpClient`). Rather than defining these as properties of the test (such as a `@Shared` property in Spock), when using `@MicronautTest` you can reference the server/context that was started up for you, and inject them directly in your test.

[source,groovy]
----
@Inject
@Inject
EmbeddedServer server //refers to the server that was started up for this test suite

@Inject
@Inject
ApplicationContext context //refers to the current application context within the scope of the test
----

### Eager Singleton Initialization

If you enable https://docs.micronaut.io/latest/guide/index.html#eagerInit[eager singleton initialization] in your application, Micronaut will eagerly initialize all singletons at startup time. This can be useful for applications that need to perform some initialization at startup time, such as registering a bean with a third party library.
sdelamo marked this conversation as resolved.
Show resolved Hide resolved

However, as tests annotated with `@MicronautTest` are implicitly in the `Singleton` scope, this can cause problems injecting some beans (for example an `HttpClient`) into your test class.

To avoid this, you can either disable eager singleton initialization for your tests, or you will need to manually get an instance of the bean you would normally inject. As an example, to get an `HttpClient` you could do:

[source,java]
----
@Inject
EmbeddedServer server; // <1>

Supplier<HttpClient> client = SupplierUtil.memoizedNonEmpty(() ->
server.getApplicationContext().createBean(HttpClient.class, server.getURL())); // <2>

@Test
void testEagerSingleton() {
Assertions.assertEquals("eager", client.get().toBlocking().retrieve("/eager")); // <3>
}
----

<1> Inject the `EmbeddedServer` as normal
<2> Create a `Supplier` that will create the `HttpClient` when it is first called
<3> Use the `Supplier` to get the `HttpClient` and make the request