0

I am trying to mock an external call along with an ArgumentMatcher to match the input values to the request. But when I trying to fetch the map from the ArgumentMatcher object, it gives me a null value.

Mockito.when(
                dynamoDbMapper.scanPage(eq(ABC.class), argThat(new ArgumentMatcher<DynamoDBScanExpression>() {

                    @Override
                    public boolean matches(Object argument)
                    {
                        DynamoDBScanExpression scanExp = (DynamoDBScanExpression) argument;
                        Assert.assertEquals("5", scanExp.getLimit());
                        Assert.assertEquals("xyz",scanExp.getFilterExpression());
                        Assert.assertEquals(new HashMap(), scanExp.getExpressionAttributeNames());

                            return true;
                    }

                }))).thenReturn(prepareScanResponse());

This expression scanExp.getExpressionAttributeNames() should ideally return a map but gives me a null value.

So suppose I have to mock a request whose input contains a map, and then try to implement ArgumentMatcher on that inout object which contains a map as an attribute, how would I do that?

mshikher
  • 174
  • 3
  • 20
  • What are you trying to accomplish? Are you trying to get a parameter to the `scanPage` method? If so, why not use the `.thenAnswer` option? I can give an example if I know what you are trying to do. – Sven Apr 01 '19 at 13:59
  • I am trying to match the request parameters which I am passing in the scanPage function of DynamoDB as DynamoDBScanExpression. DynamoDBScanExpression contains a map parameter which I am sending in the request in actual code. Now I want to match this argument here in this test under ArgumentMatcher. – mshikher Apr 01 '19 at 14:02

1 Answers1

1

Why not use a @Captor? Captors are used to get record parameters passed to methods. It seems like a cleaner way than to try to misuse a matcher.

@ExtendWith(MockitoExtension.class)
class MarketplaceHttpConnectorImplTest {
    @Captor
    ArgumentCaptor<DynamoDBScanExpression> scanExpressionCaptor;

    @Mock
    DynamoMapper dynamoDbMapper; // or something like this

    @InjectMocks
    MyClassToTest sut; // System Under Test

    @Test
    public void myTest() {
        // prepare mocks
        when(dynamoDbMapper.scanPage(eq(ABC.class), any(DynamoDBScanExpression.class)).thenReturn(prepareScanResponse());

        // Now call the method to test
        sut.methodToCall();

        // Verify calls
        verify(dynamoDbMapper, times(1)).scanPage(eq(ABC.class), scanExpressionCaptor.capture());
        DynamoDBScanExpression param = scanExpressionCaptor.getValue();

        // now test what was passed to the method.
        assertNotNull(param);
        // .....
    }
}

Btw: don't mind the JUnit5. It also works in JUnit4. Also, I presumed there was just one value. You can capture multiple values in one @Captor and check all values.

Sven
  • 2,343
  • 1
  • 18
  • 29
  • Just wanted to enquire, why didn't it worked with ArgumentMatcher? Why was the map fetched from the object of ArgumentMatcher was null? – mshikher Apr 01 '19 at 19:11
  • The only reason I can think of is that the `scanExp` does not contain the map in `.getExpressionAttributeNames()`. If the asserts before that one do work, there is no reason why the object would be 'half' constructed. So then the test found a bug perhaps? – Sven Apr 02 '19 at 04:24