Reputation: 81
I have a simple Micronaut Lambda Application and am having difficulty in successfully getting Mocks injected in to my unit tests.
build.gradle
micronaut {
runtime("lambda")
testRuntime("junit5")
...
}
With the following basic Controller
@Controller
public class MyController{
Service service;
@Inject
public Controller controller(Service service){
this.service = service;
}
@Post("/test")
public void someEndpoint(){
service.doSomething();
}
}
And the following test class:
@MicronautLambdaTest
public class MyControllerTest{
@Inject
Service service;
@Inject
@Client("/")
RxHttpClient rxHttpClient;
@MockBean(Service.class)
Service service() {
return mock(Service.class);
}
@Test
void should_do_something_when_something(){
rxHttpClient.toBlocking().exchange(HttpRequest.POST("/test",""));
verify(service, times(1)).doSomething();
}
}
The test above will fail as the mock is never interacted with.
When debugging I can see that the Service
is mocked in the test class itself, but in the MyController
class there is an actual object being used.
I notice that when I am not using runtime("lambda")
(e.g. runtime("netty")
) this works as expected, so I think this is something to do with the Lambda runtime, and am hoping someone may be able to point me in the right direction here.
Upvotes: 1
Views: 1011
Reputation: 170
When using runtime("lambda")
, you need to start the test using your handler class and remove the @MicronautTest
.
MicronautLambdaHandler handler = new MicronautLambdaHandler();
This will start the application context.
You can also pass arguments using ApplicationContext.builder()
ApplicationContextBuilder config = ApplicationContext.builder()
.environments("test");
MicronautLambdaHandler handler = new MicronautLambdaHandler(config);
Running the test with @MicronautTest
and runtime("lambda")
runs two set of environment separately that's why I removed the @MicronautTest
.
If you still want to mock classes. You can create a mock class and annotate it with @Replaces(ClassToMock.class)
and @Requires
.
For me it's @Requires(env = Environment.TEST)
.
For classes that is not an implementation of an interface, you need to extend the class you want to mock (I'm using v2.5.6).
@Replaces(ClassToMock.class)
@Requires(env = Environment.TEST)
@Singleton
public class MockClass extends ClassToMock {
@Override
public void someMethod() {}
}
For classes that implements an interface, you can simply create another implementation and annotate it likewise.
Upvotes: 3