Grails: как выполнить модульное тестирование командного объекта с введенной в него службой - PullRequest
5 голосов
/ 10 ноября 2009

Я пытаюсь проверить контроллер у которого есть объект Command с привязкой данных.

Командный объект имеет сервис, введенный в него.

Но, когда я пытаюсь проверить объект команды, внедренный метод обслуживания никогда не найден, поскольку он никогда не "вводится"

Есть ли способ смоделировать службу внутри объекта команды?

Метод испытания

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 () пользовательской службы не найден

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

В объект Command добавлен пользовательский сервис.

Валидатор вызывает эту службу пользователя для поиска пользователя

 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)

    }
}

Ответы [ 2 ]

11 голосов
/ 10 ноября 2009

Внедрение сервиса выполняется с использованием Spring-по-имени. (Grep исходное дерево Grails для autowire, чтобы найти хороший фрагмент кода, который вы можете использовать для автоматического подключения ваших контроллеров для вас в интеграционных тестах.) Это работает только в интеграционных тестах, где есть контекст приложения Spring, который имеет бобы, которые можно вводить.

В модульных тестах вы должны делать это самостоятельно, поскольку вокруг ваших вещей нет Spring-land. Это может быть больно, но дает вам некоторые преимущества:

1) Легко внедрить фиктивные версии сервисов - например, используя Expando - чтобы более точно указать поведение взаимодействующих сервисов вашего контроллера и позволить вам тестировать только логику контроллера, а не Контроллер и сервис вместе. (Конечно, вы также можете выполнить последнее в модульном тесте, но у вас есть выбор, как его подключить.)

2) Это заставляет вас четко указывать на зависимости вашего контроллера - если вы зависите от него, ваши тесты покажут это. Это делает их лучшей спецификацией поведения вашего контроллера.

3) Вы можете издеваться только над внешними сотрудниками, от которых зависит ваш контроллер. Это помогает вашим тестам быть менее хрупкими - с меньшей вероятностью их придется менять, когда что-то меняется.

Краткий ответ: вашему методу тестирования нужна строка cmd.userService = userService.

8 голосов
/ 10 ноября 2009

То, что говорит Джон, находится на отметке. Одним из примеров может быть:

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

...