Параметризованный HttpEntity в ArgumentMatcher не работает

Я провожу несколько тестов с использованием Mockito, и мой тест выполняется успешно с неправильным параметром в общем коде HttpEntity.

@UnitTest
@RunWith(MockitoJUnitRunner.class)
public class NicoMailingStrategyUnitTest {


    @Mock RestTemplate restTemplate;
    @InjectMocks NicoMailingStrategy nicoMailingStrategy;

    @Test
    public void sendTest() {

        nicoMailingStrategy.send(StubProvider.getEmailMessageModelStub());
    
        Mockito.verify(restTemplate, Mockito.times(1)).exchange(
             Mockito.eq(NicoMailingStrategy.API_ENDPOINT),
             Mockito.eq(HttpMethod.POST),
             ArgumentMatchers.<HttpEntity<FakeSendEmailDTO>>any(), // This DTO is wrong!!
             Mockito.eq(String.class));
    

}

В третьем параметре метода обмена я вставляю в HttpEntity тело типа «FakeSendEmailDTO», но реальный вызов метода использует «NicoSendEmailDTO», в любом случае тест проходит хорошо! Я жду, пока он выдаст ошибку, потому что настоящий метод не использует этот DTO.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
58
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

ArgumentMatchers.any() не проверяет тип аргумента (как в документации для любого()) и также будет соответствовать null (у которого нет типа). Свидетель типа нужен только для устранения неоднозначности между различными перегрузками одного и того же метода (например, вы используете методы-заглушки count(Stream<?>) и count(Collection<?>)). В коде даже нет возможности получить доступ к фактическому параметру типа во время выполнения просто потому, что он недоступен во время выполнения.

Если вам нужен сопоставитель, который проверяет тип аргумента, то <T> T Any(Class<T>) — это то, что вам нужно. Но это не решает вашу проблему, потому что Class<T> не имеет доступа к аргументам вложенного универсального типа, а только к типам верхнего уровня (необработанным). Он может только проверить, передали ли вы какой-либо объект, например. HttpEntity: HttpEntity<A> и HttpEntity<B> имеют один и тот же тип, когда вы запрашиваете JVM (оба HttpEntity.class). Вы можете легко проверить это утверждение самостоятельно (по теме: Что не так с дженериками Java?):

final List<String> strings = new ArrayList<String>();
final List<Integer> ints = new ArrayList<Integer>();
System.out.println(strings.getClass() == ints.getClass()); // true
// both are `ArrayList.class`, the generic type parameter is "lost"

В связи с этим: Java не позволяет перегружать методы на основе параметров универсального типа. Хотя вы можете использовать count(Stream<?>) и count(Collection<?>), невозможно перегрузить метод только для универсальных типов. Наличие sum(List<Integer>) и sum(List<Long>) не скомпилируется, поскольку оба метода имеют одинаковую сигнатуру (sum(List)).

Вместо этого вы можете попробовать использовать сопоставитель argThat и реализовать собственную логику для проверки аргумента:

ArgumentMatchers.argThat(entity -> entity.getBody().getClass() == FakeSendEmailDTO.class)
// or
ArgumentMatchers.argThat(entity -> entity.getBody() instanceof FakeSendEmailDTO)
// you might be required to specify the type to make the compiler happy:
ArgumentMatchers.<HttpEntity<FakeSendEmailDTO>>argThat(entity -> …)
ArgumentMatchers.argThat((HttpEntity<FakeSendEmailDTO> entity) -> …)

Обратите внимание, что это может уже возникнуть при доступе к entity.getBody() из-за неявного приведения, добавленного для общего типа возвращаемого значения. Возможно, вы можете обойти это, сопоставив вместо этого HttpEntity<Object>, а затем проверив динамический тип с помощью .getClass() или instanceof.

@JeffBowman Вы правы, изменения были поддельными. Пытаясь предоставить более подробную информацию, я запутался и в итоге испортил объяснения. Исправлю, спасибо за наводку!

knittl 11.06.2024 07:51

@JeffBowman, дайте мне знать, что вы сейчас думаете. Я попытался распутать путаницу переплетенных объяснений any() и any(Class) и стирания параметров универсального типа.

knittl 11.06.2024 08:19

Изменения выглядят хорошо! Спасибо за хороший ответ и доработку.

Jeff Bowman 11.06.2024 19:56

Спасибо за ответ, это было то, что я искал! И предоставленный контекст тоже очень помогает!

Nicolas Villacorta 11.06.2024 19:57

Другие вопросы по теме