when() 需要参数,Mockito 和 BCrypt

问题描述 投票:0回答:1

我正在尝试在项目中进行单元测试,但我一直在尝试模拟 BCrypt.checkpw 函数,我读到制作静态模拟需要某种方式来处理测试,我是不完全确定是否是这种情况或者可能是另一回事。

UsuarioController.java

    @GetMapping("lastPassword")
    public ResponseEntity<Object> lastPassword(@RequestParam(required = true) String correo, @RequestParam(required = true) String newPassword) { // Checa si la contraseña ingresada fue la ultima contraseña del usuario 
        try {
            Optional<usuarioVista> tmp = repositoryVista.findByCorreo(correo);
            Optional<Usuario> usuario = service.findById(Integer.toUnsignedLong(tmp.get().getIdUsuario())); // Se busca al usuario perteneciente al correo recibido
            String password = "$2a$14$" + usuario.get().getPassword(); // Se recoge la contraseña encriptada
            Boolean isLast = BCrypt.checkpw(newPassword, password); // Se checa si la contraseña ingresada coincide con la encriptada

            return new ResponseEntity<>(isLast, HttpStatus.OK);
        } catch (Exception e) {
            return ResponseEntity.badRequest().build();
        }
    }

UsuarioControllerTest.java

    @Test
    void lastPassword() throws Exception {
        String correo = "[email protected]";
        String newPassword = "Password123@";
        usuarioVista usuario = new usuarioVista();
        Usuario usuarioOption = mock(Usuario.class);
        Optional<usuarioVista> usuarioCorreo = Optional.of(usuario);
        Optional<Usuario> usuarioId = Optional.of(usuarioOption);
        BCrypt encriptado = mock(BCrypt.class);
        String password = "$2a$14$9SXpfOnx/waQlmHn6L3yp.L5d7wlf.ZMqVIwaDHuq8KDhppWtHi9K";
        Boolean isLast = true;

        Mockito.when(repositoryVista.findByCorreo(correo)).thenReturn(usuarioCorreo);
        Mockito.when(usuarioService.findById(33L)).thenReturn(usuarioId);
        Mockito.when(usuarioOption.getPassword()).thenReturn(newPassword);
        when(encriptado.checkpw(newPassword, password)).thenReturn(isLast);

        ResponseEntity<Object> response = controller.lastPassword(correo, newPassword);
    
        assertEquals(HttpStatus.OK, response.getStatusCode());
    }

堆栈跟踪

%TESTC  1 v2
%TSTTREE2,mx.com.ficachi.master.login.controllers.UsuarioControllerTest,true,1,false,1,UsuarioControllerTest,,[engine:junit-jupiter]/[class:mx.com.ficachi.master.login.controllers.UsuarioControllerTest]
%TSTTREE3,lastPassword(mx.com.ficachi.master.login.controllers.UsuarioControllerTest),false,1,false,2,lastPassword(),,[engine:junit-jupiter]/[class:mx.com.ficachi.master.login.controllers.UsuarioControllerTest]/[method:lastPassword()]
%TESTS  3,lastPassword(mx.com.ficachi.master.login.controllers.UsuarioControllerTest)

%ERROR  3,lastPassword(mx.com.ficachi.master.login.controllers.UsuarioControllerTest)
%TRACES 
org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
   Those methods *cannot* be stubbed/verified.
   Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.

        at mx.com.ficachi.master.login.controllers.UsuarioControllerTest.lastPassword(UsuarioControllerTest.java:148)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)

%TRACEE 

%TESTE  3,lastPassword(mx.com.ficachi.master.login.controllers.UsuarioControllerTest)

%RUNTIME8003

我尝试模拟 BCrypt 对象,使用 @MockBean 注释,但它引发了同样的错误。

java spring unit-testing testing mockito
1个回答
0
投票

你不太了解模拟是如何工作的。模拟不是针对类,而是针对类的特定对象。另外,模拟静态方法并不是一个好主意,mockito 无法做到这一点。如果您需要模拟 Bcrypt 类,我将创建一个单独的服务,在其中放置此逻辑并模拟服务本身。在你的情况下,你甚至不需要创建一个服务,因为 spring 已经有了 BcryptPasswordEncoder

示例:

@RestController
public YourControllerName {

    private final PasswordEncoder passwordEncoder;

    public YourControllerName(PasswordEncoder encoder) {
        this.passwordEncoder = encoder;
    }

    @GetMapping("lastPassword")
    public ResponseEntity<Object> lastPassword(@RequestParam(required = true) String correo, @RequestParam(required = true) String newPassword) { // Checa si la contraseña ingresada fue la ultima contraseña del usuario 
        try {
            Optional<usuarioVista> tmp = repositoryVista.findByCorreo(correo);
            Optional<Usuario> usuario = service.findById(Integer.toUnsignedLong(tmp.get().getIdUsuario())); // Se busca al usuario perteneciente al correo recibido
            String password = "$2a$14$" + usuario.get().getPassword(); // Se recoge la contraseña encriptada
            Boolean isLast = passwordEncoder.matches(newPassword, password); // Se checa si la contraseña ingresada coincide con la encriptada

            return new ResponseEntity<>(isLast, HttpStatus.OK);
        } catch (Exception e) {
            return ResponseEntity.badRequest().build();
        }
    }

要使用PasswordEncoder,您需要定义一个bean:

@Configuration
puclic class YourConfig {

    @Bean
    puclic PasswordEncoder passwordEncoder() {
        return new BcryptPasswordEncoder();
    }
}

测试将如下所示:


   @Autowired
   private YourControllerName controller;

   @MockBean
   private PasswordEncoder passwordEncoder


   @Test
    void lastPassword() throws Exception {
        String correo = "[email protected]";
        String newPassword = "Password123@";
        usuarioVista usuario = new usuarioVista();
        Usuario usuarioOption = mock(Usuario.class);
        Optional<usuarioVista> usuarioCorreo = Optional.of(usuario);
        Optional<Usuario> usuarioId = Optional.of(usuarioOption);
        String password = "$2a$14$9SXpfOnx/waQlmHn6L3yp.L5d7wlf.ZMqVIwaDHuq8KDhppWtHi9K";
        Boolean isLast = true;

        Mockito.when(repositoryVista.findByCorreo(correo)).thenReturn(usuarioCorreo);
        Mockito.when(usuarioService.findById(33L)).thenReturn(usuarioId);
        Mockito.when(usuarioOption.getPassword()).thenReturn(newPassword);
        when(passwordEncoder.matches(newPassword, password)).thenReturn(isLast);

        ResponseEntity<Object> response = controller.lastPassword(correo, newPassword);
    
        assertEquals(HttpStatus.OK, response.getStatusCode());
    }
© www.soinside.com 2019 - 2024. All rights reserved.