2009-11-09 3 views
5

Próbuję przetestować kontroler , który ma obiekt Command z powiązaniem danych.Grails: Jak testujesz obiekt polecenia za pomocą usługi wtryśniętej do niego

Obiekt polecenia zawiera usługę wstrzyknięcia.

ale gdy próbuję przetestować polecenia przedmiotem jest wstrzykiwany metoda usługa nigdy nie znaleziono, gdyż nigdy nie jest „wstrzykiwany”

Czy istnieje sposób, aby drwić usługę wewnątrz obiektu polecenia?

Metoda badania

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 
} 

getUser() Sposób userService nie znaleziono

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

kod

Sposób logowania sterownika miano,

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') 
    } 
} 

Obiekt polecenia ma "userService" wprowadzony do niego.

Walidator nazywa to userService aby znaleźć użytkownika

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() wygląda następująco.

class UserService { 

    boolean transactional = true 

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

    } 
} 

Odpowiedz

11

Usługa wtrysku odbywa się za pomocą Spring autowire-by-name. (Drzewo źródłowe Grep the Grails pod numer autowire, aby znaleźć ładny fragment kodu, którego można użyć do przetestowania kontrolerów w teście integracyjnym.) Działa to tylko w testach integracyjnych, w których istnieje kontekst aplikacji Spring, który zawiera komponenty można wstrzyknąć.

W testach jednostkowych, musisz zrobić to sam, ponieważ nie ma wiosennej ziemi otaczającej twoje rzeczy. Może to być uciążliwe, ale daje pewne korzyści:

1) Łatwo jest wstrzykiwać pozorowane wersje usług - na przykład, używając Expando - w celu dokładniejszego określenia zachowania współpracujących usług kontrolera i pozwala na testowanie tylko logiki sterownika, a nie kontrolera i usługi razem. (Z pewnością możesz to zrobić również w teście jednostkowym, ale masz wybór, jak go podłączyć.)

2) Zmusza Cię to do wyraźnego informowania o zależnościach twojego kontrolera - jeśli polegasz na to, twoje testy to pokażą. Dzięki temu są lepszą specyfikacją zachowania kontrolera.

3) Można kpić tylko z części zewnętrznych współpracowników, od których zależy twój kontroler. Pomaga to mniej wrażliwym testom - mniej prawdopodobne jest, że trzeba je zmienić, gdy coś się zmieni.

Krótka odpowiedź: Twoja metoda testowa wymaga linii cmd.userService = userService.

+0

Dzięki, to pracowała doskonale i teraz rozumiem więcej – Daxon

8

To, co mówi Jan, jest w znaku.Jednym z przykładów może być:

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 

Można odnośnika inne sposoby atrapa obiektu na http://groovy.codehaus.org/Groovy+Mocks