如何使用 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());
}
}
我正在使用 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());
}
}