2009-11-09 4 views
5

Ich versuche, einen Controller zu testen, der ein Command-Objekt mit Datenbindung hat.Grails: Wie Unit-Test ein Befehlsobjekt mit einem Dienst injiziert

In das Befehlsobjekt wird ein Dienst eingefügt.

aber wenn ich den Befehl versuchen Prüfobjekt das injizierte Service-Methode wird nie als es gefunden wird nie „injiziert“

Gibt es eine Möglichkeit, einen Dienst in einem Befehlsobjekt zu verspotten?

Prüfnorm

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 
} 

Die getUser() -Methode des Userservice nicht gefunden wird

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

-Code

Die Login-Methode der Controller aufgerufen wird,

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

In das Befehlsobjekt wird ein "userService" eingefügt.

Der Validator nennt diese Userservice um einen Benutzer zu finden

class LoginCommand { 

    def userService 

    String login 
    String password 

    static constraints = { 
     login blank:false, validator:{ val, cmd -> 
      if(!cmd.userService.getUser()){ 
      return "user.not.found" 
      } 
     } 
} 

Die userService.getUser() sieht wie folgt aus.

class UserService { 

    boolean transactional = true 

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

    } 
} 

Antwort

11

Die Service-Einspritzung erfolgt mit Spring autowire-by-name. (Grep the Grails Source Tree für autowire, um ein nettes Codefragment zu finden, das Sie verwenden können, um es in Integrationstests für Sie zu testen.) Dies funktioniert nur in Integrationstests, wo es einen Spring-Anwendungskontext gibt, der die Beans enthält kann injiziert werden.

In Komponententests müssen Sie dies selbst tun, da es kein Springland um Ihre Sachen gibt. Dies kann sehr schmerzhaft sein, bietet Ihnen aber einige Vorteile:

1) Es ist einfach, Mock-Versionen von Diensten zu injizieren - zum Beispiel mit Expando -, um das Verhalten der kollaborierenden Dienste Ihres Controllers genauer festzulegen ermöglichen es Ihnen, nur die Controller-Logik zu testen, anstatt Controller und Service zusammen. (Sie können das letztere natürlich auch in einem Komponententest tun, aber Sie haben die Wahl, wie Sie es verkabeln.)

2) Es zwingt Sie, explizit über die Abhängigkeiten Ihres Controllers zu sein - wenn Sie davon abhängen es, Ihre Tests werden es zeigen. Dies macht sie zu einer besseren Spezifikation für das Verhalten Ihres Controllers.

3) Sie können nur die Teile externer Mitarbeiter vortäuschen, von denen Ihr Controller abhängt. Dies hilft Ihnen, Ihre Tests weniger anfällig zu gestalten - weniger wahrscheinlich, wenn sich die Dinge ändern.

Kurze Antwort: Ihre Testmethode benötigt eine Linie.

+0

Danke, arbeitete diese eine Behandlung und jetzt verstehe ich mehr – Daxon

8

Was John sagt, ist in der Marke.Ein Beispiel dafür sein könnte:

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 

Sie andere Möglichkeiten, bei http://groovy.codehaus.org/Groovy+Mocks zu Mockobjekte Nachschlag kann