如何使用 Mockito 模拟密码编码器

How to mock password encoder using Mockito

我正在使用 Spring 安全性并且想对我的服务返回的密码进行单元测试。但是,由于这是加密的,我试图模拟在从 WebSecurityConfigurerAdapter.

扩展的 class 中执行此加密的方法
@Override
public void configure(AuthenticationManagerBuilder auth){
     auth.userDetailsService(userDetailsService).passwordEncoder(NoOpPasswordEncoder.getInstance());        
}

所以我正在尝试这样的事情

@Autowired
AuthenticationManagerBuilder auth;


static class PasswordEncoderTest implements PasswordEncoder {
    @Override
    public String encode(CharSequence charSequence) {
        return charSequence.toString();
    }

    @Override
    public boolean matches(CharSequence charSequence, String s) {
        return charSequence.toString().equals(s);
    }
}

@Test
void testCreateUser() throws Exception {

    UserCreateDto userCreateDto = new UserCreateDto("user", "test", "user@gmail.com", "user@gmail.com", "123456", "basic");
    User userMocked = new User(userId, "user", "test", "user@gmail.com", "user@gmail.com", "123456", "basic");

    PasswordEncoderTest passwordEncoderTest = new PasswordEncoderTest();
    passwordEncoderTest.encode("123456");
    when(auth.userDetailsService(myUserDetailsService).passwordEncoder(NoOpPasswordEncoder.getInstance())).thenReturn(auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoderTest));

    userCreateDto = userCommandService.createUser(userCreateDto);

    assertEquals(userMocked.getPassword(), userCreateDto.getPassword());
}
  

但是它失败了 DaoAuthenticationConfigurer cannot be returned by generateToken() generateToken() should return String

不确定该方法是否正确,是否是我可能做错的。

谢谢。

更新

https://github.com/francislainy/adverts-backend/tree/dev_jwt

根据我与 Plalx 的对话,我似乎应该注入密码编码器而不是 bycript,并且在主要和测试 classes 之间有不同的配置。将尝试并返回这里进行进一步的更新。

如果你的意思是集成测试...我真的不能尝试,但我认为你可以将 PasswordEncoder 配置为 @Bean 然后覆盖 bean 配置以使用非编码 PasswordEncoder.

例如

@Configuration
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired private PasswordEncoder passwordEncoder;

    @Bean public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth){
     
        auth.userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder);        
    }
}

然后在您的测试中,您将有一个 bean 定义,例如:

@Bean public PasswordEncoder passwordEncoder() {
    return new PasswordEncoderTest();
}

可能会有一些调整,但就是这样。


请注意,如果使用 configure 的唯一原因是覆盖协作者,那么您只需删除 configure 块,而是定义 PasswordEncoder & UserDetailsService豆子。

现在可以使用了。不是模拟散列,而是使用 两个不同的 bean,一个在 Configuration 下,另一个在 TestConfiguration 下。 用于测试的 bean 没有散列

主要应用的配置:

@Configuration
public class WebConfig {

    @Bean public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

测试配置:

@TestConfiguration
public class TestConfig {

    @Bean public PasswordEncoder passwordEncoder() {
       return NoOpPasswordEncoder.getInstance() ;
    }
}

测试:

@Import({TestConfig.class})
@WebMvcTest(UserCommandService.class)
class UserCommandServiceTest {

@MockBean
UserRepository userRepository;

@Autowired
private UserCommandService userCommandService;

@MockBean
private MyUserDetailsService myUserDetailsService;

@MockBean
private JwtUtil jwtUtil;

@Test
void testCreateUser() {

    User userMocked = new User(userId, "user", "test", "user@gmail.com", "123456", "user@gmail.com", "basic");
    UserCreateDto userCreateDto = new UserCreateDto("user", "test", "user@gmail.com", "123456", user@gmail.com", "basic");

    when(userRepository.save(any(User.class))).thenReturn(userMocked);

    userCreateDto = userCommandService.createUser(userCreateDto);
    assertEquals(userMocked.getPassword(), userCreateDto.getPassword());
}

}

PS:不要忘记在 class 名称上方 @Import TestConfig class。

最后是服务 class

@Service
public class UserCommandServiceImpl implements UserCommandService {

private final UserRepository userRepository;

@Autowired
private PasswordEncoder passwordEncoder;

public UserCommandServiceImpl(UserRepository userRepository) {
    this.userRepository = userRepository;
}

@Override
public UserCreateDto createUser(UserCreateDto userCreateDto) {
    User user = new User();
    user.setFirstname(userCreateDto.getFirstname());
    user.setLastname(userCreateDto.getLastname());
    user.setEmail(userCreateDto.getEmail());
    user.setUsername(userCreateDto.getUsername());
    user.setPassword(userCreateDto.getPassword());

    user = userRepository.save(user);

    return new UserCreateDto(user.getId(), user.getFirstname(), user.getLastname(), user.getUsername(), passwordEncoder.encode(user.getPassword()), user.getEmail(), user.getRole());
}
}