5

コマンド オブジェクトを持つコントローラーをデータ バインディングでテストしようとしています。

Command Object には Service が注入されています。

しかし、コマンドオブジェクトをテストしようとすると、注入されたサービスメソッドは決して「注入」されないため、見つかりません

コマンドオブジェクト内でサービスをモックする方法はありますか?

試験方法

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)

    }
}
4

2 に答える 2

11

サービス注入は、Spring autowire-by-name を使用して行われます。(Grails ソース ツリーを grep しautowireて、統合テストでコントローラーを自動配線するために使用できる適切なコード フラグメントを見つけます。) これは、統合テストでのみ機能します。注射される。

単体テストでは、自分のものを囲むスプリングランドがないため、これを自分で行う必要があります。これは面倒かもしれませんが、いくつかの利点があります。

Expando1)コントローラーの連携サービスの動作をより厳密に指定し、コントローラーとサービスを一緒にテストするのではなく、コントローラー ロジックのみをテストできるようにするために、サービスのモック バージョンを簡単に挿入できます。たとえば、 を使用します。(後者は単体テストでももちろん実行できますが、接続方法は選択できます。)

2) コントローラーの依存関係を明確にする必要があります。コントローラーに依存している場合、テストでそれが示されます。これにより、コントローラーの動作のより良い仕様になります。

3) コントローラーが依存する外部コラボレーターの部分のみをモックできます。これにより、テストの脆弱性が軽減され、状況が変化したときに変更する必要がなくなります。

簡単な答え: テスト メソッドにはcmd.userService = userService行が必要です。

于 2009-11-10T04:56:58.387 に答える
8

ジョンの言うことは的を射ている. 一例は次のとおりです。

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

オブジェクトをモックする他の方法をhttp://groovy.codehaus.org/Groovy+Mocksで検索できます。

于 2009-11-10T13:24:16.323 に答える