用 Spock 模拟对象
Mocking objects with Spock
我正在学习 Spock 框架。我在对我的项目实施一些测试时遇到问题。
我将测试写入 REST API 保存方法:
@Override
public User save(User user) {
roleRepository.findByName("ROLE_USER").ifPresent(role ->
user.setRoles(Collections.singletonList(role)));
user.setPassword(passwordEncoder.encode(user.getPassword()));
return userRepository.save(user);
}
我的测试 class 看起来像这样:
class UserServiceImplSpec extends Specification {
def userService
def userRepository = Mock(UserRepository)
def passwordEncoder = Mock(PasswordEncoder)
def roleRepository = Mock(RoleRepository)
def setup() {
userService = new UserServiceImpl(userRepository, passwordEncoder, roleRepository)
}
def 'should save user'() {
given:
def user = new User()
when:
userService.save(user)
then:
1 * roleRepository.findByName('ROLE_USER')
1 * passwordEncoder.encode(user.getPassword())
1 * userRepository.save(user)
0 * _
}
}
运行 测试后出现错误:
java.lang.NullPointerException
at com.jakub.shop.service.impl.UserServiceImpl.save(UserServiceImpl.java:28)
at com.jakub.shop.service.impl.UserServiceImplSpec.should save user(UserServiceImplSpec.groovy:47)
我知道我必须在我的 roleRepository 中模拟一些东西,但我不知道是什么。
可能是角色列表。我尝试了很多方法,但没有用。我应该怎么做才能正确编写此测试?我知道我的rest方法写对了
您没有从 findByName
或 encode
调用中返回任何内容。您应该返回适当的值并检查它们是否被正确使用,如下所示:
def 'should save user'() {
given:
def user = new User()
final String encodedPassword = 'pAsSwOrD'
User saved
when:
userService.save(user)
then:
1 * roleRepository.findByName('ROLE_USER') >> Optional.empty()
1 * passwordEncoder.encode(user.password) >> encodedPassword
1 * userRepository.save(_) >> { saved = it[0] }
0 * _
and:
encodedPassword == saved.password
saved.roles.empty
}
另请注意,您不需要 setup
方法;你可以直接说
@Subject
UserServiceImpl userService = new UserServiceImpl(userRepository, passwordEncoder, roleRepository)
更好的是,您可能想查看数据驱动测试的文档并拥有多个这样的测试用例:
where:
userRole || expected
null || emptyList()
ROLE_OBJ || [ROLE_OBJ]
我正在学习 Spock 框架。我在对我的项目实施一些测试时遇到问题。
我将测试写入 REST API 保存方法:
@Override
public User save(User user) {
roleRepository.findByName("ROLE_USER").ifPresent(role ->
user.setRoles(Collections.singletonList(role)));
user.setPassword(passwordEncoder.encode(user.getPassword()));
return userRepository.save(user);
}
我的测试 class 看起来像这样:
class UserServiceImplSpec extends Specification {
def userService
def userRepository = Mock(UserRepository)
def passwordEncoder = Mock(PasswordEncoder)
def roleRepository = Mock(RoleRepository)
def setup() {
userService = new UserServiceImpl(userRepository, passwordEncoder, roleRepository)
}
def 'should save user'() {
given:
def user = new User()
when:
userService.save(user)
then:
1 * roleRepository.findByName('ROLE_USER')
1 * passwordEncoder.encode(user.getPassword())
1 * userRepository.save(user)
0 * _
}
}
运行 测试后出现错误:
java.lang.NullPointerException
at com.jakub.shop.service.impl.UserServiceImpl.save(UserServiceImpl.java:28)
at com.jakub.shop.service.impl.UserServiceImplSpec.should save user(UserServiceImplSpec.groovy:47)
我知道我必须在我的 roleRepository 中模拟一些东西,但我不知道是什么。 可能是角色列表。我尝试了很多方法,但没有用。我应该怎么做才能正确编写此测试?我知道我的rest方法写对了
您没有从 findByName
或 encode
调用中返回任何内容。您应该返回适当的值并检查它们是否被正确使用,如下所示:
def 'should save user'() {
given:
def user = new User()
final String encodedPassword = 'pAsSwOrD'
User saved
when:
userService.save(user)
then:
1 * roleRepository.findByName('ROLE_USER') >> Optional.empty()
1 * passwordEncoder.encode(user.password) >> encodedPassword
1 * userRepository.save(_) >> { saved = it[0] }
0 * _
and:
encodedPassword == saved.password
saved.roles.empty
}
另请注意,您不需要 setup
方法;你可以直接说
@Subject
UserServiceImpl userService = new UserServiceImpl(userRepository, passwordEncoder, roleRepository)
更好的是,您可能想查看数据驱动测试的文档并拥有多个这样的测试用例:
where:
userRole || expected
null || emptyList()
ROLE_OBJ || [ROLE_OBJ]