#java #spring-boot #integration-testing #spring-boot-test
#java #spring-boot #интеграция-тестирование #spring-boot-test
Вопрос:
У меня возникли проблемы с интеграционным тестированием моего приложения SpringBoot.
Это базовая структура моего тестируемого класса:
@Controller
@RequiredArgsConstructor
public class PushNotificationController {
private final PushNotificationService pnSvc;
private final PushNotificationRepository pnRepo;
private final DeviceTokenRepository dtRepo;
/**
* This method sends all PushNotifications from memory,
* which are not sent yet.
*/
public List<MiddlemanResponse> send() {
List<MiddlemanResponse> middlemanResponses = pnSvc.sendAll(dtRepo.findBySendStatus(DeviceTokenEntity.Status.SCHEDULED));
return middlemanResponses;
}
}
Как вы можете видеть, это зависит от двух репозиториев, которые являются интерфейсами, расширяющимися от JpaRepository и Service-class. Все они вводятся через lombok RequiredAllArgs-constructor.
Внутри моего теста я общаюсь с базой данных H2, которая работает нормально, а также я хочу издеваться pnSvc
.
Вот мой тестовый класс:
@RunWith(SpringRunner.class)
@SpringBootTest
public class PushNotificationControllerIntegrationTest {
@Autowired
private PushNotificationController underTest;
@Autowired
private DeviceTokenRepository dtRepo;
@Autowired
private PushNotificationRepository pnRepo;
@MockBean //we mock this dependency because we dont want to send actual notifications
private PushNotificationService pnSvc;
//testvalues
private final Long FIRST_PUSH_NOTIFICATION_ID = 1L;
private final Long FIRST_DEVICE_TOKEN_ID = 1L;
PushNotificationEntity pushNotification = new PushNotificationEntity(FIRST_PUSH_NOTIFICATION_ID, "message", "customString", 1L, "metadata");
DeviceTokenEntity deviceToken = new DeviceTokenEntity(FIRST_DEVICE_TOKEN_ID, "deviceToken", pushNotification, DeviceTokenEntity.Platform.IPHONE, "applicationType","brandId", DeviceTokenEntity.Status.SCHEDULED);
@Before
public void setUp() throws MiddlemanException {
when(pnSvc.sendAll(dtRepo.findBySendStatus(DeviceTokenEntity.Status.SCHEDULED))).thenReturn(List.of(new MiddlemanResponse(deviceToken, "response_message")));
pnRepo.save(pushNotification);
dtRepo.save(deviceToken);
}
@Test
public void sendOneSuccessTest() {
List<MiddlemanResponse> responses = underTest.send();
assertEquals(1, responses.size());
}
}
К сожалению, издевательский метод pnSvc.sendAll(...)
возвращает null
, поэтому список MiddlemanResponse пуст, и мой тест завершается неудачей с:
org.opentest4j.AssertionFailedError: expected: <1> but was: <0>
Expected :1
Actual :0
Я ожидаю, что издевательский метод должен вернуть установленное значение List.of(new MiddlemanResponse(deviceToken, "response_message")
.
РЕШЕНИЕ Благодаря dbl и Джанлуке Муса за ваши ответы я пошел с подходом Джанлуки Мусы использовать any() вместо передачи фактического параметра -> pnSvc.sendAll(any())
при издевательстве над ответом
Также я не использовал предложенный Джанлукой Мусой, org.mockito.Matchers.any
а org.mockito.Mockito.any
скорее из-за его устаревания.
Комментарии:
1. Макет возвращает
null
значение по умолчанию, если вы не укажете конкретное значение, которое будет возвращено…2. В случаях
when(that.doThis(someVal).thenReturn(blah)
вам следует использовать сопоставитель… Нравитсяwhen(that.doThis(eq(someVal)).thenReturn(blah)
Ответ №1:
Вероятно, ошибка в том, что фильтр для макета неверен, вы можете использовать универсальный селектор для имитации sendAll (), попробуйте это
when(pnSvc.sendAll(org.mockito.Mockito.any()).thenReturn(List.of(new MiddlemanResponse(deviceToken, "response_message")));
Комментарии:
1.
any
тоже вариант, но он может быть еще более конкретным в зависимости от требований теста.2. это сработало, но я использовал org.mockito. Для этого тестового случая достаточно Mockito.any вместо устаревшего предлагаемого @dbl any