Grails的:你如何单元测试命令对象与注入到它的服务
-
19-09-2019 - |
题
我试图测试控制器 具有与数据绑定一个命令对象。
命令对象具有注入到它的服务。
但是当试图测试命令对象所注入的服务方法 从未发现,因为它是从不“注入”
有一种方法来模拟一个命令对象内的服务?
<强>测试方法强>
void testLoginPasswordInvalid() {
mockRequest.method = 'POST'
mockDomain(User, [new User(login:"freddy", password:"realpassword")])
mockLogging(UserService) // userService mocked
MockUtils.prepareForConstraintsTests(LoginCommand)
def userService = new UserService()
def user = userService.getUser("freddy")//Gets called and returns the mockDomain
assert userService.getUser("freddy")//Passes
def cmd = new LoginCommand(login:"freddy", password:"letmein")
cmd.validate() // Fails (userService is nevr injected)
controller.login(cmd)
assertTrue cmd.hasErrors()
assertEquals "user.password.invalid", cmd.errors.password
assertEquals "/store/index", renderArgs.view
}
的userService的的getUser()方法没有找到
Cannot invoke method getUser() on null object
java.lang.NullPointerException: Cannot invoke method getUser() on null object
<强>代码强>
控制器的登录方法被调用,
def login = { LoginCommand cmd ->
if(request.method == 'POST') {
if(!cmd.hasErrors()){
session.user = cmd.getUser()
redirect(controller:'store')
}
else{
render(view:'/store/index', model:[loginCmd:cmd])
}
}else{
render(view:'/store/index')
}
}
命令对象具有 “userService” 注入其中。
在验证器调用此userService找到一个用户
class LoginCommand {
def userService
String login
String password
static constraints = {
login blank:false, validator:{ val, cmd ->
if(!cmd.userService.getUser()){
return "user.not.found"
}
}
}
在userService.getUser()看起来像这样。
class UserService {
boolean transactional = true
User getUser(String login) {
return User.findByLogin(login)
}
}
解决方案
服务注入使用Spring自动装配按姓名进行。 (GREP Grails的源树autowire
找到你可以用它来得到它的自动装配你的控制器为您在集成测试一个漂亮的代码片段。)这只功能集成测试,其中有一个Spring应用程序上下文周围有豆谓可以注入。
在单元测试中,你必须这样做你自己,因为有你的周围没有任何东西Spring的土地。这可以是一个痛苦,但给你一些好处:
1),可以很容易地注入服务的模拟版本 - 例如,使用Expando
- 为了更紧密地指定你的控制器的协作服务的行为,并允许您仅测试控制器逻辑而不是控制器和一起服务。 (你当然可以做后者在单元测试为好,但你有如何连接起来的选择。)
2),它迫使你要明确你的控制器的依赖 - 如果你依赖于它,你的测试将证明这一点。这使得他们更好地规范控制器的行为。
3)可以仅嘲笑外部合作者的片控制器取决于。这有助于你的测试是那么脆弱 - 不太可能需要当事情变来变去。
短的答案:测试方法需要cmd.userService = userService
线
其他提示
什么约翰说,是上的标记。一个例子可以是:
def mockUsers = [new User(login:"freddy", password:"realpassword")]
mockDomain(User, mockUsers)
def userService = [getUser:{String login -> mockUsers[0]}] as UserService
def cmd = new LoginCommand (/*arguments*/)
cmd.userService = userService
不隶属于 StackOverflow