2009-11-09 18 views
5

데이터 바인딩이있는 Command 객체를 가진 컨트롤러 을 테스트하려고합니다.Grails : 서비스를 삽입 한 커맨드 객체를 어떻게 단위 테스트합니까?

명령 개체에 서비스가 주입되었습니다. 내가 명령을 테스트 할 때이

명령 객체 내부의 서비스를 조롱 할 수있는 방법이 있나요 "주입 없다"결코로

그러나 주입 된 서비스 방법 이 발견되지 않습니다 객체?

userService의 인 getUser() 메소드

Cannot invoke method getUser() on null object 
java.lang.NullPointerException: Cannot invoke method getUser() on null object 

코드

컨트롤러 로그인 메소드가 호출되고 발견되지

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 
} 

시험 방법,

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"가 삽입되어 있습니다.

유효성 검사기는

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()이 보이는 사용자를 찾으려면이 userService를 호출합니다.

class UserService { 

    boolean transactional = true 

    User getUser(String login) { 
     return User.findByLogin(login) 

    } 
} 

답변

11

서비스 삽입은 Spring autowire-by-name을 사용하여 수행됩니다. (grep the Grails 소스 트리 autowire을 사용하면 통합 테스트에서 컨트롤러를 autowire하기 위해 사용할 수있는 멋진 코드 조각을 찾을 수 있습니다.)이 기능은 통합 테스트에서만 작동합니다. 주입 할 수 있습니다.

단위 테스트에서는 물건을 둘러싼 스프링 랜드가 없기 때문에 직접 테스트해야합니다. 이는 고통이 될 수 있지만 이점을 제공합니다.

1) 컨트롤러의 공동 작업 서비스의 동작을보다 자세히 지정하기 위해 Expando과 같은 서비스 모의 버전을 쉽게 삽입 할 수 있습니다. 컨트롤러와 서비스가 아닌 컨트롤러 로직 만 테스트 할 수 있습니다. (단위 테스트에서 확실히 후자를 수행 할 수 있지만 와이어를 연결하는 방법을 선택할 수 있습니다.)

2) 컨트롤러의 종속성에 대해 명시 적으로 지정해야합니다. 그것, 당신의 시험은 그것을 보여줄 것이다. 이는 컨트롤러의 동작에 대한 더 나은 사양을 제공합니다.

3) 컨트롤러가 의존하는 외부 공동 작업자 만 조롱 할 수 있습니다. 이렇게하면 테스트가 약해져서 상황이 바뀔 때 변경해야 할 필요성이 줄어 듭니다.

짧은 대답 : 테스트 방법은 cmd.userService = userService 라인이 필요합니다.

+0

감사 모의 객체에 다른 방법을 조회 할 수

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 

,이 치료 을 근무하고 지금은 이해가 더 – Daxon

관련 문제