I have Quarkus/Jakarta REST API. It contains a CDI bean which is annotated with @Startup. In short, it’s initializing the main service class for that REST API.
My code looks like this:
@Path("/proxy")
public class ProxyResource {
@Inject
ApiManager apiManager;
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response proxy() {
String response = apiManager.fetchResponse();
return Response.ok(response).build();
}
}
@Startup
public class ApiManager {
public ApiManager() {
logger.info("Actual ApiManager constructor");
}
public String fetchResponse() {
return "expected response";
}
}
By using @Startup I’m sure that when POST /proxy endpoint is called then apiManager object is already created and, most importantly, its constructor was invoked before actual API request. In this constructor I’m performing some “warmup” operations such as registering tasks for java.util.concurrent.ScheduledExecutorService
.
I’m creating simple integration tests for POST /proxy endpoint. I want to mock ApiManager so that I can control its behavior and that I can focus the test on testing actual responses from that API.
My test currently looks like this:
@QuarkusTest
class ProxyResourceTest {
@InjectMock
private ApiManager apiManagerMock;
@Test
void testProxyEndpointReturns200AndResponse() {
String payload = "expected response";
Mockito.when(apiManagerMock.fetchResponse()).thenReturn(payload);
given().contentType(ContentType.JSON)
.body(payload)
.when().post("/proxy")
.then()
.statusCode(200)
.body(is(payload));
}
}
}
So here is my actual problem: When I execute quarkus test
I can see that the constructor of ApiManager is executed. Most likely Quarkus does not inject the mock, but it’s injecting the actual object. If I change ApiManager annotation from @Startup to @ApplicationScoped (only for test run purpose), then tests are running as expected, mock is being injected thus constructor is not being executed.
Question:
How can I mock a @Startup CDI bean in the test so I can fully control behavior of the mocked object (and set expectations for mock; and – in that case – constructor won’t be executed)?
Most likely Quarkus does not inject the mock, but it’s injecting the actual object.
@Startup
is actually translated to an observer method of StartupEvent
which is always fired when the app starts.
If I change ApiManager annotation from @Startup to @ApplicationScoped (only for test run purpose), then tests are running as expected, mock is being injected thus constructor is not being executed.
This way no StartupEvent
observer is registered and thus ApiManager
is not created in order to receive the event.
How can I mock a @Startup CDI bean in the test so I can fully control behavior of the mocked object (and set expectations for mock; and – in that case – constructor won’t be executed)?
Well, you can use quarkus.arc.test.disable-application-lifecycle-observers=true
to disable StartupEvent
/ShutdownEvent
observers declared on bean classes during the tests.
But I’m not completely sure it would help in your use case…