#java #spring #unit-testing #junit #mockito
#java #spring #модульное тестирование #junit #mockito
Вопрос:
Я пишу некоторый тестовый код в Spring Boot JUnit, и тестирование прошло успешно с использованием метода репозитория, "when, thenReturn"
как показано ниже.
@ExtendWith(SpringExtension.class)
@WebMvcTest
public class PictionarizerapiUserControllerTests {
@MockBean
private UserRepository userRepository;
@MockBean
private UserController userController;
@Autowired
private MockMvc mockMvc;
@Test
@DisplayName("When an update request is sent, the User data gets updated properly, and the updated User data gets returned in a form of JSON")
public void testUpdateUser() throws Exception {
// User before update
User existingUser = new User();
existingUser.setId(28);
existingUser.setName("Alex");
......
......
// return the User (before update) that is fetched by UserRepository#findById() with ID=28
when(userRepository.findById(28)).thenReturn(Optional.of(existingUser));
// UserRepository#save() returns the fetched entity as it is
when(userRepository.save(any())).thenAnswer((invocation) -> invocation.getArguments()[0]);
......
......
Я подумал, что мог бы также написать тестовый пример для метода контроллера, который я написал сам, и я попытался выполнить «when, thenReturn» следующим образом.
@Test
@DisplayName("When correct login information is given and the matched user is fetched")
public void testCheckIfValidUserFound() throws Exception {
Integer userIdObj = Integer.valueOf(28);
String requestEmail = "alex.armstrong@example.com";
String requestPassword = "MajorStateAlchemist";
when(userController.checkIfValidUser(requestEmail, requestPassword)).thenReturn(Optional.of(userIdObj));
......
......
}
Однако я получил сообщение об ошибке The method thenReturn(ResponseEntity<capture#1-of ?>) in the type OngoingStubbing<ResponseEntity<capture#1-of ?>> is not applicable for the arguments (Optional<Integer>)
. Я провел некоторое исследование и пришел к пониманию, что вы можете использовать "when, thenReturn"
синтаксис только при тестировании методов репозитория, которые встроены в методы в JPA, такие как findById()
etc (если я не ошибаюсь), И в моем случае это не работает, потому что я пытаюсь протестировать метод, который я создал самостоятельно, а не метод, встроенный в репозиторий JPA.
И здесь возникает мой вопрос. Как я могу написать что-то, что эквивалентно "when, thenReturn"
, когда я тестирую что-то, отличное от метода репозитория?
Обновить
Вот как определяется мой собственный метод.
@RequestMapping(value = "/login", method = RequestMethod.GET)
public ResponseEntity<?> checkIfValidUser(
@RequestParam("email") String email,
@RequestParam("password") String password) {
int userId = 0;
List<User> userList = repository.findAll();
for(User user: userList) {
String userEmail = user.getEmail();
String userPassword = user.getPassword();
String inputEmail = email;
String inputPassword = password;
if(userEmail.equals(inputEmail) amp;amp; userPassword.equals(inputPassword)) {
userId = user.getId();
}
}
if(userId > 0) {
Integer userIdObj = Integer.valueOf(userId);
return new ResponseEntity<>(userIdObj, HttpStatus.OK);
} else {
return new ResponseEntity<>(
new Error("The email address and the password don't match"),
HttpStatus.NOT_FOUND
);
}
}
Комментарии:
1. » Я провел некоторое исследование и пришел к пониманию, что синтаксис «when, thenReturn» можно использовать только при тестировании методов репозитория, которые встроены в методы в JPA » — Вы можете сослаться на источник? В общем, можно проверить все вызовы в mocks. — Сообщение об ошибке предполагает, что
userController.checkIfValidUser(...)
возвращает что-то отличное отOptional<Integer>
. Название метода предполагает, может быть,boolean
?2. Как
checkIfValidUser
определяется?3. @Turing Боюсь, я не помню ссылку. Что касается утверждения «вы можете использовать «when, thenReturn» синтаксис работает только тогда, когда …», это всего лишь моя гипотеза, и я не полностью уверен, правильно ли это (вот почему я добавил (если я не ошибаюсь).
4. @luk2302 Я обновил свой первоначальный пост, и теперь вы можете видеть, как
checkIfValidUser
определяется.5. И вы можете видеть, что он возвращает
ResponseEntity<?>
, а не aOptional<Integer>
, типы должны совпадать.
Ответ №1:
Поскольку кажется, что метод, который вы хотите протестировать, является testCheckIfValidUserFound()
, вы не должны издеваться над самим методом подобным образом.
when(userController.checkIfValidUser(requestEmail, requestPassword)).thenReturn(Optional.of(userIdObj));
Вместо этого метод, который вы должны имитировать, является userRepository.findAll()
потому что это метод репозитория, который вы вызываете внутри checkIfValidUser
метода в вашем контроллере.
Итак, ваша часть «when, thenReturn» должна выглядеть следующим образом.
when(userRepository.findAll()).thenReturn(Collections.singletonList(esixtingUser));
и когда вы хотите проверить, возвращает ли тест правильное значение, обычно вам нужно указать, значение какого ключа вы хотите проверить, но в этом случае, согласно вашему checkIfValidUser
методу, он просто возвращает целое число, если поиск успешен, поэтому при утверждении с помощью jsonPath
не должно быть никаких спецификаций вместе со знаком доллара.
Итак, после того, как вы смоделируете репозиторий, вы можете выполнить запрос get следующим образом.
mockMvc.perform(MockMvcRequestBuilders.get("/login")
.param("email", requestEmail)
.param("password", requestPassword)
.with(request -> {
request.setMethod("GET")<
return request;
}))
.andExpect(MockMvcResultMatchers.status().is(HttpStatus.OK.value()))
.andExpect(jsonPath("$").value(28));