Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return a list when unit testing DynamoDB PaginatedQueryList

I have a query statement which returns a PaginatedQueryList and I assign it to a List. Then I operate on the list.

List<MyClass> entries= mapper.query(MyClass.class, queryExpression);
//Logic to test
Map<String, Map> map = entries.stream()
                        .collect(Collectors.toMap(MyClass::getA, MyClass::getB));
....
....

I tried to test it like

when(mapper.query(eq(MyClass.class), any(DynamoDBQueryExpression.class)))
                              .thenReturn((PaginatedQueryList<MyClass>) list);

where list is List<MyClass>(ArrayList) that I construct myself and want to pass it to the main program to test the main logic.

But it throws

java.lang.ClassCastException: java.util.ArrayList cannot be cast to com.amazonaws.services.dynamodbv2.datamodeling.PaginatedQueryList

How can I send the list when it executes mappper.query(..).

The motive is to send the list that I constructed to entries when executing mapper.query(..).

NOTE:

I also tried sending a mocked PaginatedQueryList but when it does entries.stream() I want to send the actual stream. I tried like

when(paginatedQueryList.stream()).thenReturn(Stream.of(list.get(0), list.get(1)));

It throws

java.lang.IllegalStateException: stream has already been operated upon or closed at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229)

NOTE 2:

I use entries.stream() twice in my logic to test

like image 904
user7 Avatar asked Mar 28 '16 03:03

user7


People also ask

What is paginated query list?

Class PaginatedQueryList<T>Paginated results are loaded on demand when the user executes an operation that requires them. Some operations, such as size(), must fetch the entire list, but results are lazily fetched page by page when possible.

What is DynamoDBMapper?

The DynamoDBMapper class is the entry point to Amazon DynamoDB. It provides access to a DynamoDB endpoint and enables you to access your data in various tables. It also enables you to perform various create, read, update, and delete (CRUD) operations on items, and run queries and scans against tables.


3 Answers

Mockito has some powerful tools for this.

List<MyClass> list = new ArrayList<>();
when(mapper.query(eq(MyClass.class), any(DynamoDBQueryExpression.class)))
    .thenReturn(mock(PaginatedQueryList.class, withSettings().defaultAnswer(new ForwardsInvocations(list))));

This will return a mocked PaginatedQueryList which forwards all method calls to list.

like image 83
MikeFHay Avatar answered Nov 07 '22 02:11

MikeFHay


I was able to solve the problem by sending mocked PaginatedQueryList and then send list.stream() twice (for each access of entries.stream()).

when(paginatedQueryList.stream()).thenReturn(list.stream()).thenReturn(list.stream());

Any better approaches are welcome.

like image 38
user7 Avatar answered Nov 07 '22 03:11

user7


My answer is a generic solution for mocking PaginatedQueryList in tests (might be useful for googlers, since there's not much answers for this topic).

For my test this worked:

    // given
    List<UserDevice> expectedDevices = Arrays.asList(generateUserDevice(USER_ID, DEVICE_ID), generateUserDevice(USER_ID, "deviceId2"));

    PaginatedQueryList listMock = mock(PaginatedQueryList.class);
    when(listMock.listIterator()).thenReturn(expectedDevices.listIterator());
    when(mapper.query(eq(UserDevice.class), any(DynamoDBQueryExpression.class))).thenReturn(listMock);

    // when
    List<UserDevice> devices = dao.findAll(USER_ID);

    // then
    assertEquals(expectedDevices, devices);

so, as you can see, I mocked the PaginatedQueryList and mocked its listIterator() method.

like image 2
Reynard Avatar answered Nov 07 '22 04:11

Reynard