0

I am trying to mock a very simple line of code that is used to query the DynamoDB using Java. Here is some sample code for the query -

List<Pojo> result;
        try {
            if (filters == null) {
                this.queryExpression = new DynamoDBQueryExpression<Pojo>()
                        .withKeyConditionExpression(partitionKeyCondition)
                        .withExpressionAttributeValues(this.eav);
            } else {
                setFilterQueryExpression(filters);
            }
            result = this.dynamoDBMapper.query(Pojo.class, queryExpression);
        } catch (final Exception e) {
            throw new InternalServerException("Something went wrong with the database query: ", e);
        }

The above piece of code works and I am able to retrieve a List of rows that automatically get deserialized into the Pojo.

I am now trying to Mock the this.dynamoDBMapper.query call as follows -

@Mock
private DynamoDBMapper mapper;
List<Pojo> result = new ArrayList<>();

when(mapper.query(Pojo.class,Mockito.any(DynamoDBQueryExpression.class)).thenReturn(result);

I am unable to do that with error -

Cannot resolve method 'thenReturn(java.util.List<com.amazon.xxx.xxx.Pojo>)'

I also tried another way -

doReturn(result).when(mapper).query(Pojo.class, Mockito.any(DynamoDBQueryExpression.class));

That seems to compile but the test fails with error -

org.mockito.exceptions.misusing.WrongTypeOfReturnValue 

I have looked at other sample where the expected output of the query is of type PaginatedQueryList , I have tried changing to that as well. But I am still not sure why the above throws an error.

Samarth
  • 242
  • 2
  • 12
  • Have you tried changing List to PaginatedQueryList or similar? According to the documentation the query methods return specific implementations of List. You can assign a specific implementation to a more general List variable but you cannot return a more general type where a specific implementation is requested per the signature. Hence, Mockito cannot resolve the method you are asking for. – Bastis Programming Corner Jan 27 '22 at 22:24
  • I did try changing the return type from `List` to `PaginatedQueryList` but the `when` still does not accept it. It says `Cannot resolve method 'thenReturn(PaginatedQueryList)'`. I feel like I need to do something extra to make it work but I am not entirely sure how. – Samarth Jan 27 '22 at 23:05

2 Answers2

0

Do you also get the error when you use ArgumentMatchers?

Mockito.when(mapper.query(ArgumentMatchers.any(Pojo.class),ArgumentMatchers.any(DynamoDBQueryExpression.class)).thenReturn(result));

Do you also get the error if you expand the ArgumentMatchers (temporarily)?

Mockito.when(mapper.query(ArgumentMatchers.any(),ArgumentMatchers.any()).thenReturn(result));
dcnis
  • 61
  • 4
  • Yes, it does not change anything. I have already tried replacing the arguments with `any()`. – Samarth Jan 27 '22 at 22:20
  • @Samarth Can you go into the .query() method and check the return type? Is it List or is it a base class? WrongTypeOfReturnValue and Cannot resolve method List<...Pojo> hints somehow that the return value is false. Also check if the return value is something like List extends something> because then your Pojo need to extend "something" as well. – dcnis Jan 27 '22 at 22:29
  • The return type is `PaginatedQueryList` as described in the documentation. I have tried switching all the return types in my code from `List` to `PaginatedQueryList` but I still run into the error. See comment on question for more. – Samarth Jan 27 '22 at 23:07
0

As it turns out, you are missing a parenthesis before .thenReturn in order to complete the when part. Once you add it and switch from return type List to PaginatedQueryList, it should compile. Also note that any is a matcher. Once you specifiy a matcher, all arguments need to be matchers, therefore use eq etc. for your Pojo type. Otherwise, Mockito will show a InvalidUseOfMatchersException during runtime. Here is a simplified example that works for me:

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBQueryExpression;
import com.amazonaws.services.dynamodbv2.datamodeling.PaginatedQueryList;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class MockTest {

    @Test
    void test() {
        DynamoDBMapper mapperMock = mock(DynamoDBMapper.class);
        PaginatedQueryList<String> expected = mock(PaginatedQueryList.class);
        // Note that when needs to be completed before thenReturn can be called.
        when(mapperMock.query(eq(String.class), Mockito.any(DynamoDBQueryExpression.class))).thenReturn(expected);

        QueryService queryService = new QueryService(mapperMock);
        PaginatedQueryList<String> actual = queryService.query();

        assertEquals(expected, actual);
    }

    public class QueryService {
        private final DynamoDBMapper mapper;

        public QueryService(DynamoDBMapper mapper) {
            this.mapper = mapper;
        }

        public PaginatedQueryList<String> query() {
            DynamoDBQueryExpression<String> queryExpression = new DynamoDBQueryExpression<>();
            return mapper.query(String.class, queryExpression);
        }
    }
}