首页 > 解决方案 > 测试非存储库方法时如何执行与“when,thenReturn”等效的操作

问题描述

我正在 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()等(除非我弄错了),在我的情况下它不起作用,因为我要测试的是我自己创建的方法,而不是 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) && 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
            );
        }
    }

标签: javaspringunit-testingjunitmockito

解决方案


由于您要测试的方法似乎是testCheckIfValidUserFound(),您不应该像这样模拟方法本身。

when(userController.checkIfValidUser(requestEmail, requestPassword)).thenReturn(Optional.of(userIdObj));

相反,您应该模拟的方法是因为这是您在控制器userRepository.findAll()的方法中调用的存储库方法。checkIfValidUser

所以你的“when,thenReturn”部分应该是这样的。

when(userRepository.findAll()).thenReturn(Collections.singletonList(esixtingUser));

并且当您要检查测试是否返回正确的值时,通常您需要指定要检查的键的值,但是在这种情况下,根据您的checkIfValidUser方法,如果搜索成功,它只会返回一个整数,所以应该有用jsonPath.

因此,在您模拟存储库之后,您可以像这样执行获取请求。

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));

推荐阅读