Как выборочно установить свойство с помощью DEPENDENCY INJECTION в сервисе grails для модульного тестирования - PullRequest
0 голосов
/ 21 июня 2011

РЕДАКТИРОВАТЬ: Пожалуйста, дайте мне пояснить, я спрашиваю, как сделать это в Grails, используя Spring Dependency Injection, а НЕ функциональность метакласса Grails или new ().

У меня есть служба grails для анализа файлов журнала. Внутри сервиса я использую текущее время для множества вещей. Для модульного тестирования у меня есть несколько примеров файлов журналов, которые я анализирую с помощью этого сервиса. У них есть времена в них, очевидно.

Я хочу, чтобы моя служба DURING UNIT TESTING думала, что текущее время не превышает нескольких часов после последнего оператора записи в моих файлах журналов примера.

Итак, я готов к этому:


class MyService {
    def currentDate = { -> new Date() }

    def doSomeStuff() {
        // need to know when is "right now"
        Date now = currentDate()
    }
}

Итак, что я хочу сделать - это ввести currentDate или установить его в другое HARDCODED время, например

currentDate = { -> new Date(1308619647140) }

Нет ли способа сделать это с помощью какого-нибудь макета, каким бы способом я ни занимался в моем модульном тесте? Подобные вещи были очень просты с Google Guice, но я понятия не имею, как это сделать весной.

Довольно обидно, что когда я Google "внедряю зависимость от grails", все, что я нахожу, это примеры


class SomeController {
  // wow look how amazing this is, it's injected automatically!!
  // isn't spring incredible OMG!
  def myService
}

Мне кажется, что все, что мне показывает, это то, что мне не нужно вводить новый ... ()

Где мне сказать, что когда среда равна тесту, тогда сделайте это:


currentDate = { -> new Date(1308619647140) }

Я просто застрял, устанавливая это свойство вручную в моем тесте ??

Я бы предпочел не создавать "службу времени", потому что это кажется глупым, учитывая, что я просто хочу 1 крошечное изменение.

Ответы [ 3 ]

1 голос
/ 26 июня 2011

Спасибо за помощь, ребята. Лучшее решение, которое я мог придумать для использования Spring DI в этом случае, заключалось в следующем:

resources.groovy

Вот два решения, которые я нашел:
1: Если я хочу, чтобы timeNowService менялся везде для целей тестирования:

import grails.util.GrailsUtil

// Place your Spring DSL code here
beans = {
    if (GrailsUtil.environment == 'test') {
        println ">>> test env"
        timeNowService(TimeNowMockService)
    } else {
        println ">>> not test env"
        timeNowService(TimeNowService)
    }
}


2: Я мог бы сделать это, если я только хочу, чтобы это изменение применялось к этой конкретной услуге:

import grails.util.GrailsUtil

// Place your Spring DSL code here
beans = {

    if (GrailsUtil.environment == 'test') {
        println ">>> test env"
        time1(TimeNowMockService)
    } else {
        println ">>> not test env"
        time1(TimeNowService)
    }
    myService(MyService) {
        diTest = 'hello 2'
        timeNowService = ref('time1')
    }
}


В любом случае я бы воспользовался услугой по телефону timeNowService.now(). Одна странная и очень расстраивающая вещь для меня заключалась в том, что я не мог сделать это:

import grails.util.GrailsUtil
// Place your Spring DSL code here
beans = {
    if (GrailsUtil.environment == 'test') {
        println ">>> test env"
        myService(MyService) {
            timeNow = { -> new Date(1308486447140) }
        }
    } else {
        println ">>> not test env"
        myService(MyService) {
            timeNow = { -> new Date() }
        }
    }
}

На самом деле, когда я пытался это сделать, у меня также было фиктивное значение, например dummy = 'hello 2', а затем значение по умолчанию dummy = 'hello' в самом классе myService. И когда я сделал этот третий пример с фиктивным значением, установленным там, он молча не смог установить, очевидно, что b / c timeNow взорвал что-то в приват.

Мне было бы интересно узнать, может ли кто-нибудь объяснить, почему это не удается.

Спасибо за помощь, ребята, и извините за нетерпение ...

1 голос
/ 21 июня 2011

Groovy - динамический язык, и поэтому он позволяет вам почти делать то, что вы просите:

class MyServiceTests extends GrailsUnitTestCase {
    def testDoSomeStuff() {
        def service = new MyService()
        service.currentDate = { -> new Date(1308619647140) }

        // assert something on service.doSomeStuff()
    }
}

Имейте в виду, что это только изменяет serviceэкземпляр, а не класс.Если вам нужно изменить класс, вам нужно работать с metaClass.Взгляните на этот пост от mrhaki .

Другой вариант - сделать текущую дату параметром doSomeStuff().Таким образом, вам не нужно будет изменять экземпляр службы.

0 голосов
/ 21 июня 2011

Поскольку Groovy является динамическим, вы можете просто убрать свой метод currentDate () из службы и заменить его на тот, который соответствует вашим потребностям. Вы можете сделать это во время выполнения во время настройки вашего теста.

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

MyService.metaClass.currentDate << {-> new Date(1308619647140) }

Таким образом, вы можете иметь согласованное поведение во всех ваших тестах.

Однако, если вы предпочитаете, вы можете переопределить метод экземпляра с помощью замыкания, которое выполняет тот же трюк.

Дайте мне знать, как это происходит.

Винсент Жигер

...