Reputation: 107
I have Quarkus app and I am trying to test my reactive Controller REST APIs using RestAssured.
And I am using smallrye-mutiny for developing my REST APIs.
The issue is when running the test RestAssured is trying to serialize the Uni and it throwing the following exception saying it could not found a serializer for Uni type. :
Caused by:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of
`io.smallrye.mutiny.Uni` (no Creators, like default constructor, exist): abstract types either
need to be mapped to concrete types, have custom deserializer, or contain additional type
information
at [Source: (String)
{
"header":{
"statusCode":"99-9999",
"statusDescription":"com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)"
}
}
; line: 1, column: 1]
Here is how my code looks like:
My Service Layer:
import io.smallrye.mutiny.Uni;
@ApplicationScoped
public class AccountOpeningServiceImpl implements AccountOpeningService {
@Override
public Uni<GetRandomNumberResponseApi> getRandomNumber(GetRandomNumberRequestApi requestApi) {
Uni<GetRandomNumberResponseApi> numberUni = Uni.createFrom().item(() -> GetRandomNumberResponseApi.builder().number(10).build()))
return numberUni;
}
My Controller :
import io.smallrye.mutiny.Uni;
@Path("")
public class AccountOpeningController {
@Inject
AccountOpeningService accountOpeningService;
@POST
@Path("/random-number")
public Uni<GetRandomNumberResponseApi> getRandomNumber(@Valid GetRandomNumberRequestApi requestApi) {
return accountOpeningService.getRandomNumber(requestApi);
}
And finally here is my test how it looks like.
@QuarkusTest
public class AccountOpeningControllerTest {
@InjectMock
AccountOpeningService accountOpeningService;
@Inject
MockUtil mockUtil;
@Test
void getRandomNumber() throws IOException {
GetRandomNumberRequestApi requestApi = mockUtil.getMock("Get_Random_Number_Request.json",
GetRandomNumberRequestApi.class);
GetRandomNumberResponseApi responseApi = mockUtil.getMock("Get_Random_Number_Response.json",
GetRandomNumberResponseApi.class);
when(accountOpeningService.getRandomNumber(requestApi)).thenReturn(Uni.createFrom().item(responseApi));
Uni<GetRandomNumberResponseApi> response = given()
.contentType(MediaType.APPLICATION_JSON)
.body(requestApi)
.when()
.post("/get-random-number")
.then()
.statusCode(200)
.extract()
.as(new TypeRef<Uni<GetRandomNumberResponseApi>>() {
});
GetRandomNumberResponseApi actualResponse = response.subscribe()
.withSubscriber(UniAssertSubscriber.create())
.assertCompleted()
.getItem();
Assertions.assertEquals(responseApi, actualResponse);
}
Any help, advices, resources?
Upvotes: 1
Views: 693
Reputation: 107
After 18 hours of searching
I came to know that I need to add quarkus-resteasy-mutiny
to my pom.xml
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-mutiny</artifactId>
</dependency>
I think this dependency contains the Uni serializer by default.
Upvotes: 0
Reputation: 3316
That's because RestAssured tries to serialize a mock object. That mock object has extra properties like mockitoInterceptor
and so on. And one or more of those properties in the tree are not serializable by Jackson.
So use real objects as request body and as expected response.
The following test will work
@QuarkusTest
class ExampleResourceTest {
@InjectMock
RandomNumberService service;
@Test
void testRandomNumberEndpoint() {
// create a real (not mocked) request object
var request = new RandomNumberRequestDTO();
request.setUpper(500L);
request.setLower(3L);
// create a real (not mocked) response object
var expectedResponse = new RandomNumberResponseDTO(3L, 500L, 399L);
// mock service with real request and response object
Mockito.when(service.getRandomNumber(request)) //pass real request object
.thenReturn(Uni.createFrom().item(expectedResponse)); // pass real response object
var resp =
given()
.when()
.body(request) // pass real request object
.contentType(ContentType.JSON)
.post("/random-number")
.then()
.statusCode(200)
.extract()
.as(RandomNumberResponseDTO.class);
assertAll(
() -> assertNotNull(resp),
() -> assertEquals(request.getLower(), resp.getLower()),
() -> assertEquals(request.getUpper(), resp.getUpper()),
() -> assertThat(resp.getRandomNumber(), is(both(greaterThanOrEqualTo(resp.getLower())).and(lessThan(resp.getUpper()))))
);
}
}
Upvotes: 0