Java 验证使用BCryptPasswordEncoder编码的密码时,断言失败
我有非常简单的Java 验证使用BCryptPasswordEncoder编码的密码时,断言失败,java,unit-testing,mockito,Java,Unit Testing,Mockito,我有非常简单的UserCreator服务 @Service public class UserCreator { private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; public UserCreator(UserRepository userRepository, PasswordEncoder passwordEncoder) {
UserCreator
服务
@Service
public class UserCreator {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public UserCreator(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
public CreateUserResult createUser(CreateUserCommand command) {
validate(command);
return new CreateUserResult(doCreateUser(command).getId());
}
private User doCreateUser(CreateUserCommand command) {
final var user = User.builder()
.password(passwordEncoder.encode(command.getPassword()))
.email(command.getEmail())
.birthDate(command.getBirthDate())
.build();
return userRepository.save(user);
}
}
我添加了几个单元测试,其中一个测试验证是否创建了用户编码的密码
@ExtendWith(MockitoExtension.class)
public class UserCreatorTest {
@Mock
private UserRepository userRepository;
private UserCreator userCreator;
private PasswordEncoder passwordEncoder;
@BeforeEach
public void setUp() {
this.passwordEncoder = new BCryptPasswordEncoder();
this.userCreator = new UserCreator(userRepository, passwordEncoder);
}
@Test
@DisplayName("Created user has encoded password")
void test2() {
final var userCaptor = ArgumentCaptor.forClass(User.class);
when(userRepository.save(any())).thenReturn(User.builder().build());
final var command = CreateUserCommand.builder()
.email("test@test.pl")
.password("test123")
.birthDate(LocalDate.of(1990, 10, 10))
.build();
final var expectedPassword = passwordEncoder.encode(command.getPassword());
userCreator.createUser(command);
verify(userRepository, times(1)).save(userCaptor.capture());
assertTrue(passwordEncoder.matches(expectedPassword, userCaptor.getValue().getPassword()));
}
}
但是,此测试在assertTrue()
上失败,这些密码不匹配
为什么会这样?当我使用
BCryptPasswordEncoder
处理身份验证时,我检查了应用程序的另一部分,它实际上为我解决了这个问题
而不是做
final var expectedPassword = passwordEncoder.encode(command.getPassword());
assertTrue(passwordEncoder.matches(expectedPassword, userCaptor.getValue().getPassword()));
我应该这么做
assertTrue(passwordEncoder.matches(command.getPassword(), userCaptor.getValue().getPassword()));
现在我的测试通过了。
BCryptPasswordEncoder#encode
不是确定性的。它将包含一个随机salt,因此您的expectedPassword
和doCreateUser
中的passwordEncoder.encode
不一定匹配。使用一个mockPasswordEncoder
,或者(可能不值得)传入一个mockSecureRandom
,这样两个调用都匹配。关于调用新的BCryptPasswordEncoder()
-我确实在调用它,但正如您所看到的,相同的isntance被传递到服务并在单元测试中使用。这里我没有使用两个不同的实例。