Работает ли сопоставление с argThat только для методов с одним аргументом?


У меня есть следующий вызов метода в моем тестируемом классе:

class ClassUnderTest {
   [...]
    restTemplate.getForEntity(url, MyResponseEntity.class, parameterMap);
   [...]
}

В модульном тесте класса, содержащего эту строку, я хочу заглушить метод getForEntity таким образом, чтобы он возвращал разные ответы для разных записей в parameterMap. Используя BDDMockito, я пытаюсь сопоставить, что нужный параметр является частью parameterMap, используя argThat:

@InjectMocks
private ClassUnderTest classUnderTest;

@Mock
private RestTemplate restTemplate;

[...]

given(restTemplate.getForEntity(anyString(), any(Class.class), argThat(hasEntry("myKey", "myValue"))
   .willReturn(responseEntityA);

Однако, если я выполняю тест таким образом, что parameterMap содержит (Я проверил это в отладчике) ключ " myKey" и значение "myValue", я получаю NullPointerException, потому что mockito, кажется, не может сопоставить вызов метода с заглушкой, которую я создал.

С другой стороны, использование следующего очень общего сопоставления позволяет мне выполнять мои тесты без NPE, предоставляя ответ по умолчанию для всех вызовов, однако это не позволяет мне определить пользовательский ответ для данного параметра.

given(restTemplate.getForEntity(anyString(), any(Class.class), anyMap())
  .willReturn(defaultResponseEntity);

В чем причина этого? Работает ли argThat только для методов с одним параметром? Есть другой способ сопоставить вызовы getEntity с картой, содержащей определенную пару (ключ, значение)?

2 2

2 ответа:

argThat безусловно, работает для более чем одного параметра, и нет ничего явно неправильного в том, что вы пытаетесь сделать. У меня есть ноющее предчувствие, что он выбирает неправильную перегрузку :

getForEntity(String url, Class<T> responseType, Map<String,?> urlVariables)
getForEntity(String url, Class<T> responseType, Object... urlVariables)

Если генераторы не совсем совпадают, Java может предположить, что ваш hasEntry лучше всего соответствует методу Object..., где ваш anyMap соответствует методу Map<String, ?>. В этом случае вы бы заглушили перегрузку, которую вы не вызываете (Object...), и Mockito вернулся бы к значениям по умолчанию для того, который вы вызываете. фактически вызывая тестируемую систему (Map<String, ?>). Наведение указателя мыши на вызов метода в IDE может пролить свет на то, какая перегрузка соответствует компилятору.

Чтобы дать Java лучшую подсказку, попробуйте приведение, которое будет выглядеть так (предупреждение, не проверено или проверено):

given(restTemplate.getForEntity(
         anyString(),
         any(Class.class),
         (Map<String, ?>) argThat(hasEntry("myKey", "myValue"))))
    .willReturn(responseEntityA);    

Я не уверен, почему argThat не работает для вас, но вы можете попробовать использовать thenAnswer и проверить аргументы в вашем Answer.