mockitoquarkusjunit5rest-assuredquarkus-testing

Cannot get Quarkus/Mockito to use @InjectMock instance - wrong data is returned from endpoing testing


I have a pretty simple Quarkus REST application that reads/writes to Redis. When writing my endpoint tests (using the Quarkus mocking guide), I can't get the data to return from the mock. Instead, it looks like it's using a non-mock injection and returning a non-null and empty list.

Here is dependency order. I want to mock RedisService:

DataEndpointResource -> DataService -> RedisService

DataEndpointResource:

@Path("/data")
@RequestScoped
public class DataEndpointResource {

    @Inject
    DataService service;

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getAllValues() {

        Collection<DataRecord> values;
        try {
            values = service.getAllValues();
        } catch (RedisException ex) {
            return Response.serverError().build();
        }

        return Response.ok(values).build();

    }
}

DataService:

@RequestScoped
public class DataService {
    
    @Inject
    private RedisService redisService;

    public Collection<DataRecord> getAllValues() throws RedisException {
        
        return this.redisService.getAllValues();
        
    }
}

RedisService:

@ApplicationScoped
public class RedisService {
    
    ReactiveRedisDataSource ds;
    
    KeyCommands<String> keyCommands;
    ValueCommands<String, ObjectLockRecord> valueCommands;
    
    public RedisService(RedisDataSource ds) {
        
        keyCommands = ds.key();
        valueCommands = ds.value(ObjectLockRecord.class);
        
    }
    
    public Collection<DataRecord> getAllValues() throws RedisException {
        try {
            // do redis stuff and return values
        } catch (Exception ex) {
            log("Error obtaining values", ex);
            throw new RedisException(ex);
        }
    }
}

Test:

@QuarkusIntegrationTest
public class DataEndpointResourceIT extends DataEndpointResourceTest {
    
}
import io.quarkus.test.InjectMock;
import io.quarkus.test.junit.QuarkusTest;
import static io.restassured.RestAssured.given;
import io.restassured.common.mapper.TypeRef;
import io.restassured.http.ContentType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestMethodOrder;
import static org.mockito.Mockito.when;

@QuarkusTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@DisplayName("Data REST Resource")
public class DataEndpointResourceTest {

    @InjectMock
    RedisService redisServiceMock;

    Map<String, DataRecord> testData;

    @BeforeEach
    public void setUp() throws RedisException {

        testData = new HashMap<>();

        DataRecord r = new DataRecord("1234", "data1");
        testData.put(r.getKey(), r);
        r = DataRecord r = new DataRecord("asdf", "data2");
        testData.put(r.getKey(), r);

    }

    @Test
    @Order(1)
    @DisplayName("Endpoint: GET /data")
    public void getData() throws RedisException // without "throws" it complains {        

        when(redisServiceMock.getAllValues()).thenReturn(new ArrayList<>(testData.values()));

        List<DataRecord> list = given()
                .accept(ContentType.JSON)
                .when()
                .get("/api/v1/data")
                .then()
                .statusCode(200)
                .extract().body().as(new TypeRef<>() {
                });

        Assertions.assertNotNull(list);
        Assertions.assertEquals(2, list.size());

    }

}

It always fails:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
|
+-- Data REST Resource
| +-- [XX] Endpoint: GET /data - 0.728 ss

Results:

Failures: 
  DataEndpointResourceTest.getData:79 expected: <2> but was: <0>

Solution

  • If you run only the Quarkus test DataEndpointResourceTest the mock should work. You can't inject beans in a @QuarkusIntegrationTest, resp. it will have no effect.

    The Quarkus doc describes how to write Quarkus integration tests: https://quarkus.io/guides/getting-started-testing#quarkus-integration-test

    See also this answer for difference between normal Quarkus tests and integration tests: Quarkus @QuarkusTest vs @QuarkusIntegrationTest