Search code examples
mockitoargument-matcher

Map is not getting populated for ArgumentMatcher object


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?


Solution

  • 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.