Как сохранить метакласс сервиса от переопределения

Я пытаюсь смоделировать вызов внешнего сервиса в интеграционном тесте, сервис используется в веб-потоке grails. Служба не входит в поток или область диалога, но добавляется через внедрение зависимостей, см. Здесь.

Мне удалось найти способ переопределить службу, заменив ее метакласс с помощью ExpandoMetaClass. Изменения работают только тогда, когда тест запускается один. Если другой тест, использующий ту же службу, выполняется до этого теста, изменения метакласса пропадают.

Часть, которая переопределяет метакласс:

static {
    ExpandoMetaClass someService = new ExpandoMetaClass(Object, false)
    someService.invokeMethod = { String name, args ->
        def result = 'success'
        if(name.equals('accessAnotherSystem')
        {
            StackTraceUtils.sanitize(new Throwable()).stackTrace.each
            {
                if(it.methodName.equals('test_method_I_Want_failure_in')
                {
                    result = 'exception'
                }
            }
            return result
        }

        def validMethod = SomeService.metaClass.getMetaMethod(name, args)
        if (validMethod != null)
        {
            validMethod.invoke(delegate, args)
        }
        else
        {
            SomeService.metaClass.invokeMissingMethod(delegate, name, args)
        }
    }
    someService.initialize()
    SomeService.metaClass = someService
}

Смежный вопрос: Как изменить метакласс класса для каждого теста

Есть ли способ сохранить мои изменения для теста или есть какой-то другой способ переопределить службу.

1 ответ

Существует более простой способ, если вы хотите переопределить службу в тестовом примере для каждого метода тестирования. Посмотрите на пример:

class SomeControllerSpec extends Specification {

    def someService

    void "test any external method for success response"() {
        given: "Mocked service method"
        someService.metaClass.accessAnotherSystem = { arg1, arg2 ->
            return "some success response"
        }

        when: "Any controller method is called which calls this service method"
        // Your action which calls that service method

        then: "Result will processed coming from mocked method"
        // Your code
    }
}

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

class SomeServiceSpec extends Specification {

    def someService

    void "test external method call"() {
        given: "Mocked service method"
        someService.metaClass.methodA = { arg1, arg2 ->
            return "some success response"
        }

        when: "A method is called which invokes the another method"
        // Your another service method which call the same method
        someService.methodB()    // Where methodB() invokes the methodA() internally in your code

        then: "Result will processed coming from mocked method"
        // Your code
    }
}
Другие вопросы по тегам