Дразнить функцию реального объекта с помощью Спока - PullRequest
0 голосов
/ 15 октября 2019

Я хочу добавить несколько тестов Controller Unit для веб-приложения, написанного с помощью инфраструктуры Grails.
Мне нужно пропустить getMessage() метод, который использовался в методе cancel_request() в контроллере как реальный объект.

class PublicControllerSpec extends Specification implements ControllerUnitTest<PublicController> {

 def "Cancel Request for user"() {
    given:
    controller.getMessage() << Spy(PublicController){
        getMessage(_ as User, _ as String) >> "SuccessMessage"
    }

    when:
    controller.cancel_request()

    then:
    response.redirectedUrl.contains('/public/list')
  }
}

1 Ответ

1 голос
/ 16 октября 2019

Отказ от ответственности: у меня нет никакого опыта работы с платформой Grails, но я работал с Spock

Исходя из вашего вопроса:

Вы говорите: контроллер - это реальный объект, поэтому он долженбыть создан с кодом, подобным следующему в тесте:

controller = new SomeController(<dependencies>)

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

Так что в основном у вас есть два способа:

Вариант 1: шпионить за контроллером

Сам контроллер должен быть шпионом: это то, что оборачивает реальный объект (реальный контроллер) и по умолчанию делегирует все вызовы методов этому внутреннему реальному объекту, если вы не «подавляете» эту функциональность(в этом случае вы говорите что-то вроде: ведите себя как реальный объект, но если кто-то вызывает getMessage, тогда возвращает сообщение вместо делегирования реальному объекту). Очевидным недостатком этого способа является то, что тестируемый объект (контроллер) становится шпионом, что на самом деле не очень хороший подход.

Вариант 2: Рефакторинг кода

Признаюсь, поскольку у меня нет опыта работы с Grails, я мог бы что-то здесь упустить, но если контроллер - это код, который вы написали, вы можете выбрать следующее изменение:

Ввести зависимость: класс, который отвечает за вычисление сообщений, например:

 interface MessageCalculator {
     String getMessage()
 }

 class MyController {
      MessageCalculator messageCalculator 
      MyController(MessageCalculator messageCalculator) {
         this.messageCalculator = messageCalculator
      }


      public getMessage() {
           messageCalculator.getMessage()
      }
 }

Sidenote: Да, я знаю, что здесь могут быть применимы преобразования AST, но это не предмет вопроса, поэтому яоставим такой код

В любом случае, теперь вы можете повторно выполнить тест следующим образом:

   def "test me now"() {
      given:
         def msgCalc = Stub(MessageCalculator)
         msgCalc.getMessage() >> "Successfull message"

         def controller = new MyController(msgCalc)
      ...  
   }
...