我正在尝试测试 Controller
有一个带有数据绑定(bind)的 Command 对象。

命令对象有一个注入(inject)其中的服务。

但是当我尝试测试命令对象注入(inject)的服务方法时
从未被发现,因为它从未“注入(inject)”

有没有办法在命令对象中模拟服务?

测试方法

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 

代码

被调用的 Controller 的登录方法,
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”注入(inject)其中。

验证器调用此 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) 
 
    } 
} 

请您参考如下方法:

服务注入(inject)是使用 Spring autowire-by-name 完成的。 (Grails 源代码树 autowire 找到一个很好的代码片段,您可以使用它在集成测试中为您 Autowiring Controller 。)这仅在集成测试中起作用,其中有一个 Spring 应用程序上下文具有可以注入(inject)的 bean 。

在单元测试中,你必须自己做这件事,因为你的东西周围没有 Spring-land。这可能会很痛苦,但会给您带来一些好处:

1) 很容易注入(inject)模拟版本的服务 - 例如,使用 Expando - 为了更详细地指定 Controller 协作服务的行为,并允许您仅测试 Controller 逻辑而不是 Controller 和服务一起测试。 (你当然也可以在单元测试中做后者,但是你可以选择如何连接它。)

2)它迫使你明确 Controller 的依赖关系——如果你依赖它,你的测试会显示它。这使它们成为 Controller 行为的更好规范。

3)您只能模拟您的 Controller 所依赖的外部协作者。这有助于您的测试不那么脆弱——当事情发生变化时不太可能需要改变。

简短回答:您的测试方法需要 cmd.userService = userService线。


评论关闭
IT干货网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!