Having trouble testing your micronaut application? Or just interested on my take on micronaut testing? Just read along! In this post we will make some integration and unit tests for a micronaut gRPC API.
For a wider view of the micronaut testing capabilities look at the guide here. For a good read on the different kinds of test go here.
We will use a micronaut application from a previous post on micronaut and gRPC. Until now we did not make tests for this application so it’s about time. The complete code for this post is found on github here.
Integration test
The details of the application are not clear for now. I can tell you that is a gRPC endpoint and it returns some dummy data. But let us test if that is true with an integration test.
We will think of the application of a black box and we will mimic a client of the API calling the gRPC endpoint. First we will create a client stub just like an actual client would have.
@Factory
class Clients {
@Bean
CatServiceGrpc.CatServiceBlockingStub blockingStub(
@GrpcChannel(GrpcServerChannel.NAME) ManagedChannel channel) {
return CatServiceGrpc.newBlockingStub(channel);
}
}
If we now annotate a test class with @MicronautTest
and inject this stub can call the running API.
@MicronautTest
public class CatApiIT {
@Inject
CatServiceGrpc.CatServiceBlockingStub blockingStub;
...
The following test now looks like any other.
@Test
void testGetCat() {
final CatRequest request = CatRequest.newBuilder()
.setChipId("92821-1231")
.build();
Cat result = blockingStub.getCat(request);
assertEquals("Freddy", result.getName());
assertEquals(5, result.getAge());
}
Cool! Our first micronaut gRPC integration test.
Unit test
We will now look at the same gRPC endpoint from a different perspective. The class of the endpoint is our unit under testing. This time we will mock other parts of the application and test only the specifics of this class.
The endpoint class is dependend on the repository class (CatRepository
). To mock this repository we will inject it in the test class.
@MicronautTest
public class CatEndpointTest {
@Inject
CatRepository catRepository;
...
But to mock it and take controle over it we need to use the @MockBean
annotation.
@MockBean(CatRepository.class)
CatRepository mathService() {
return mock(DummyCatRepository.class);
}
Note: We mock the interface in the annotation but we setup a concrete class in the mock
method from Mockito. Mockito is the mocking framework we use and is pulled with the following dependency.
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
Now we are ready for the test. We start with defining the output of our mock in this situation.
when(catRepository.findCatById(any())).thenReturn(
Optional.of(Cat.newBuilder()
.setName("Harry")
.setAge(12)
.build()));
We use the matcher any
to always return the cat object we define here when the findCatById
method is called.
Now we cannot use the stub like a client but have to call the method of the endpoint with its own method.
catEndpoint.getCat(CatRequest.newBuilder().build(), new StreamObserver<Cat>() {
@Override
public void onNext(Cat cat) {
assertEquals("Harry", cat.getName());
assertEquals(12, cat.getAge());
}
@Override
public void onError(Throwable throwable) {
fail("Should not throw error!");
}
@Override
public void onCompleted() {
// Do nothing
}
});
Note that we implement the observer that is used for the output on the fly. We fail if there is an error for we do not expect one in this case. For the onNext
method we verify the result is matching the output of the repository we mocked.
Hopefully you now have enough tools to get started with micronaut testing your (gRPC) applications. Happy testing!