【问题标题】:Mockito When...Then Return - return ignored?Mockito When...Then Return - 返回被忽略?
【发布时间】:2020-01-01 10:26:18
【问题描述】:

我目前正在学习 Spring-boot 的课程,并且我一直在测试一个项目 - 非常感谢任何帮助,因为我是这里的初学者。

我有一个休息控制器测试,使用 Mockito,当使用 Mockito.when() 调用方法时,它似乎忽略了“ThenReturn”。

这是全班:

package com.example.demo.controllers;

import com.example.demo.TestUtils;
import com.example.demo.model.persistence.AppUser;
import com.example.demo.model.persistence.repositories.CartRepository;
import com.example.demo.model.persistence.repositories.UserRepository;
import com.example.demo.model.requests.CreateUserRequest;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import java.util.Optional;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

public class UserControllerTest {

    private UserController userController;
    private UserRepository userRepository = mock(UserRepository.class);
    private CartRepository cartRepository = mock(CartRepository.class);
    private BCryptPasswordEncoder bCryptPasswordEncoder = mock(BCryptPasswordEncoder.class);

    @Before
    public void initTest(){
        userController = new UserController();
        TestUtils.injectObjects(userController, "userRepository", userRepository);
        TestUtils.injectObjects(userController, "cartRepository", cartRepository);
        TestUtils.injectObjects(userController, "bCryptPasswordEncoder", bCryptPasswordEncoder);
        AppUser appUser = TestUtils.getAppUser();
        when(userRepository.findById(0L)).thenReturn(Optional.of(appUser));
        when(bCryptPasswordEncoder.encode("testPassword")).thenReturn("hashedPassword");
    }

    @Test
    public void testFindUserById(){
        ResponseEntity<AppUser> response = userController.findById(0L);
        System.out.println(response);
    }


    @Test
    public void testCreateUser() throws Exception{

        CreateUserRequest createUserRequest = new CreateUserRequest();
        createUserRequest.setUsername("testUser");
        createUserRequest.setPassword("testPassword");
        createUserRequest.setConfirmPassword("testPassword");

        ResponseEntity<AppUser> response = userController.createUser(createUserRequest);

        assertNotNull(response);
        assertEquals(200, response.getStatusCodeValue());

        AppUser createdUser = response.getBody();
        assertNotNull(createdUser);
        assertEquals(0, createdUser.getId());
        assertEquals("testUser", createdUser.getUsername());
        assertEquals("hashedPassword", createdUser.getPassword());
    }
}

名为“testCreateUser”的测试顺利通过。给我带来问题的是名为“testFindUserById”的测试。

这是我正在尝试测试的控制器方法(在 Postman 中测试时一切正常):

public ResponseEntity<AppUser> findById(@PathVariable Long id) {
        try{
            log.info("UserIDSearch = " + id);
            System.out.println("UserIDSearch = " + id);
            Optional<AppUser> optionalAppUser = userRepository.findById(id);
            if(optionalAppUser.isPresent()){
                log.info("UserIdFound =  " + id);
                return ResponseEntity.ok(optionalAppUser.get());
            }else{
                throw new ApiException(ExceptionTypes.SEARCHUSER, id.toString());
            }
        }catch(ApiException a){
                return ResponseEntity.notFound().build();
        }
    }

在测试类中被模拟的存储库只是一个简单的 JpaRepository:

public interface UserRepository extends JpaRepository<AppUser, Long> {
    Optional<AppUser> findByUsername(String username);
    public Optional<AppUser> findById(long id);
}

运行 testFindUserById() 测试得到的输出如下:

UserIDSearch = 0
<404 NOT_FOUND Not Found,[]>

我想我在这里想要实现的是测试使用 when().thenReturn() 来模拟来自模拟 userRepository 的 OK 响应,但实际上它执行搜索并返回“未找到” .任何人都可以帮忙吗?非常感谢!

【问题讨论】:

  • 抛出的异常信息是什么?
  • 感谢您的回复!也不例外 - 它似乎完全忽略了 thenReturn(Optional.of(appUser)) 部分并实际在存储库上执行搜索 - 我不知道为什么。有点像testCreateUser() 方法模拟从bCryptPasswordEncoder 返回密码时,我试图让testFindUserById 方法模拟从存储库返回用户。
  • 从响应中似乎代码进入了 catch 块 - 不是这样吗?
  • 据我了解(可能是错误的),实际上不应执行搜索,因为 mockito 应该接听电话 Optional&lt;AppUser&gt; optionalAppUser = userRepository.findById(id); 并返回 Optional.of(appUser) ,它可用于构建返回的 ReponseEntity通过控制器方法。但这没有发生。
  • 嗯,你是个传奇。您的两个小提示使我能够使我的 4 个测试课程中的 3 个完全正常工作。非常感谢!

标签: java junit mocking mockito


【解决方案1】:

似乎是自动装箱的问题。将方法 public Optional&lt;AppUser&gt; findById(long id); 改为接受 Long。

【讨论】:

    【解决方案2】:

    我认为@Janar 是正确的,但我会解释原因。

    当您编写“when(userRepository.findById(0L)).thenReturn(Optional.of(appUser))”时,Mockito 所做的是设置开始监视对指定方法 (findById) 的调用并将参数与“0L”进行比较",这是一个Java long int,它不是一个对象。

    实际方法采用 java.lang.Long,它是一个对象。两者不相等。

    正如@Janar 建议的那样,您可以通过更改 findById 方法来修复它,但这不是我会做的。我假设生产代码出于实际原因使用 java.lang.Long 。相反,我会将测试更改为:

    when(userRepository.findById(Long.valueOf(0L))).thenReturn(Optional.of(appUser));
    

    【讨论】:

    • 谢谢你的澄清,我会做出改变的!
    【解决方案3】:

    我的情况与您的 findById 不同,但我希望它有所帮助。

    总结:

    mockito 对传递的参数很敏感,它更适用于简单或原始数据类型

    就我而言,这句话被忽略了:

    doReturn(result).when(scriptExecutor).
    runScript(connection, new StringReader("selec * from dual;"));
    

    经过几个小时的尝试,我将 runScript 的定义更改为接收 simple string 而不是 StringReader

    从这里:

    public ArrayList runScript(Connection conn, StringReader reader)
    

    到这里:

    public ArrayList runScript(Connection conn, String query)
    

    然后选择了嘲笑的句子,一切都按预期工作:

    doReturn(result).when(scriptExecutor).
    runScript(connection, "selec * from dual;");
    

    基本上,如果我使用 StringReader,则不起作用。但是用一个简单的字符串就可以了!!

    【讨论】:

      猜你喜欢
      • 2020-03-23
      • 1970-01-01
      • 2021-01-13
      • 1970-01-01
      • 2017-03-15
      • 2021-10-03
      • 1970-01-01
      • 2022-12-18
      • 1970-01-01
      相关资源
      最近更新 更多