【发布时间】:2020-03-27 11:16:43
【问题描述】:
我在服务类中有注册方法,我尝试为成功案例编写单元测试以防止重复电子邮件
public void signUp(UserDTO userDTO) {
logger.info("ActionLog.Sign up user.Start");
Optional<UserEntity> checkedEmail = userRepository.findByEmail(userDTO.getEmail());
System.out.println(checkedEmail);
if (checkedEmail.isPresent()) {
System.out.println("check email: "+checkedEmail);
logger.error("ActionLog.WrongDataException.Thrown");
throw new WrongDataException("This email already exists");
}
String password = new BCryptPasswordEncoder().encode(userDTO.getPassword());
UserEntity customerEntity = UserEntity
.builder()
.name(userDTO.getName())
.surname(userDTO.getSurname())
.username(userDTO.getEmail())
.email(userDTO.getEmail())
.password(password)
.role(Role.ROLE_USER)
.build();
userRepository.save(customerEntity);
logger.info("ActionLog.Sign up user.Stop.Success");
}
这是我的测试课
class UserServiceImplTest extends Specification {
UserRepository userRepository
AuthenticationServiceImpl authenticationService
UserServiceImpl userService
def setup() {
userRepository = Mock()
authenticationService = Mock()
userService = new UserServiceImpl(userRepository, authenticationService)
}
def "doesn't throw exception if email doesn't exist in database"() {
given:
def userDto = new UserDTO()
def entity = new Optional<UserEntity>()
userDto.setEmail("example@mail.ru")
1 * userRepository.findByEmail(userDto.getEmail()) >> entity
1 * entity.isPresent() >> false
when: "send dto object to service "
userService.signUp(userDto)
then: ""
notThrown(WrongDataException)
}
}
测试失败,因为它为我提供了 ByCryptPasswordEncoder 的 NPE: 但我不编写集成测试,我只需要测试重复的电子邮件成功和失败案例
java.lang.NullPointerException
at org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder.encode(BCryptPasswordEncoder.java:108)
at az.gdg.msauth.service.impl.UserServiceImpl.signUp(UserServiceImpl.java:41)
at az.gdg.msauth.service.UserServiceImplTest.doesn't throw exception if email doesn't exist in database(UserServiceImplTest.groovy:35)
但是,我在服务类中评论这些
String password = new BCryptPasswordEncoder().encode(userDTO.getPassword());
UserEntity customerEntity = UserEntity
.builder()
.name(userDTO.getName())
.surname(userDTO.getSurname())
.username(userDTO.getEmail())
.email(userDTO.getEmail())
.password(password)
.role(Role.ROLE_USER)
.build();
userRepository.save(customerEntity);
它给了我
Too few invocations for:
1 * entity.isPresent() >> false (0 invocations)
Unmatched invocations (ordered by similarity):
None
Too few invocations for:
1 * entity.isPresent() >> false (0 invocations)
Unmatched invocations (ordered by similarity):
None
我该如何解决这个问题?
【问题讨论】:
-
您需要引入一个抽象级别,使您能够控制新的 BCryptPasswordEncoder().encode。然后使用依赖注入能够在单元测试期间提供模拟,以及生产代码的真实实现。 BCryptPasswordEncoder 是否实现了接口?
-
当然,如果你要做
1 * entity.isPresent() >> false,你需要给实体一个密码让Encoder编码? -
我是 spock 框架的新手。我只想测试块的成功和失败情况,而不是密码编码器。因为它属于spring。不幸的是,当测试开始时,它会从上到下读取所有代码在服务中,当到达编码器时会抛出异常。我的问题是,我如何才能测试只有阻塞
-
欢迎来到 SO。请阅读MCVE 文章,了解如何提出好的问题,以及如果您想获得好的答案,为什么 MCVE 如此有价值。谢谢。
-
至于你的
NullPointerException,没有MCVE我只能推测userDTO.getPassword()是null,因为在你的测试中你忘了初始化密码,正如蒂姆已经说过的那样。
标签: java unit-testing groovy spock