Граали:Как вы проводите модульное тестирование командного объекта с внедренной в него службой

StackOverflow https://stackoverflow.com/questions/1703952

Вопрос

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

В командный объект внедрена Служба.

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

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

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

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

Командный объект имеет введенный в него "пользовательский сервис".

Валидатор вызывает этот пользовательский сервис, чтобы найти пользователя

 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)

    }
}
Это было полезно?

Решение

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

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

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

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

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

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

Другие советы

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top