Как сделать что-то эквивалентное «when, thenReturn» при тестировании метода, не связанного с репозиторием

#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<?> , а не a Optional<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));