2009-11-09 15 views
5

J'essaie de tester un contrôleur qui a un objet Command avec liaison de données.Grails: Comment testez-vous un objet de commande avec un service injecté dedans

L'objet de commande a un service injecté dedans.

Mais quand j'essaie de tester la commande objet de la méthode de service injecté est jamais trouvé qu'il est jamais « injecté »

est-il un moyen de se moquer d'un service à l'intérieur d'un objet de commande?

Méthode d'essai

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 
} 

Procédé getUser() de la UserService ne se trouve pas

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

code

La méthode de connexion de l'unité de commande étant appelée,

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

L'objet de commande a un "userService" injecté dedans.

Le validateur appelle ce UserService pour trouver un utilisateur

class LoginCommand { 

    def userService 

    String login 
    String password 

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

Le userService.getUser() ressemble à ceci.

class UserService { 

    boolean transactional = true 

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

    } 
} 

Répondre

11

injection de service est effectuée à l'aide autowire par nom Spring. (Grep the Grails source tree pour autowire pour trouver un fragment de code sympa que vous pouvez utiliser pour obtenir automatiquement vos contrôleurs dans les tests d'intégration.) Cela fonctionne uniquement dans les tests d'intégration, où il y a un contexte d'application Spring qui a les beans peut être injecté.

Dans les tests unitaires, vous devez le faire vous-même car il n'y a pas de Spring-terrain qui entoure vos affaires. 1) Il est facile d'injecter des versions fictives de services - par exemple, en utilisant un Expando - afin de spécifier plus précisément le comportement des services de collaboration de votre automate, et de vous permet de tester uniquement la logique du contrôleur plutôt que le contrôleur et le service ensemble. (Vous pouvez certainement faire ce dernier dans un test unitaire, mais vous avez le choix de la connexion.)

2) Cela vous oblige à être explicite sur les dépendances de votre contrôleur - si vous dépendez de vos tests le montreront. Cela en fait une meilleure spécification du comportement de votre contrôleur.

3) Vous pouvez simuler uniquement les éléments de collaborateurs externes dont dépend votre contrôleur. Cela aide vos tests à être moins fragiles - moins susceptibles de devoir changer lorsque les choses changent.

Réponse courte: votre méthode de test nécessite une ligne cmd.userService = userService.

+0

Merci, cela a fonctionné un régal et maintenant je comprends plus – Daxon

8

Ce que John dit est sur la marque.Un exemple pourrait être:

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 

Vous pouvez rechercher d'autres façons d'objets fantaisie à http://groovy.codehaus.org/Groovy+Mocks