Я провожу несколько тестов с использованием 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.




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, дайте мне знать, что вы сейчас думаете. Я попытался распутать путаницу переплетенных объяснений any() и any(Class) и стирания параметров универсального типа.
Изменения выглядят хорошо! Спасибо за хороший ответ и доработку.
Спасибо за ответ, это было то, что я искал! И предоставленный контекст тоже очень помогает!
@JeffBowman Вы правы, изменения были поддельными. Пытаясь предоставить более подробную информацию, я запутался и в итоге испортил объяснения. Исправлю, спасибо за наводку!