Как проверить Grails 3 контроллера с сервисами, которые имеют другие сервисы в них?

В случаях модульного тестирования контроллеров я могу вводить только те службы, которые используются в соответствующем контроллере. Но если, скажем, одна служба в контроллере внедряет другую службу, мои тестовые примеры терпят неудачу, т.е. не могут вызвать метод службы для нулевого объекта.

@TestFor(MyController)
@Mock(MyService)
class MyControllerSpec extends Specification {
    void "test something"(){
        when:
            controller.method1();
        then:
            //something
    }

}

class MyController(){
    MyService myService

    void method1(){
        myService.serviceMethod()       
    }   
}

class MyService(){
    AnotherService anotherService
    void serviceMethod(){
        anotherService.anotherServiceMethod()
    }
}

class AnotherService(){
    void anotherServiceMethod(){
    \\something
    }
}

в этом случае я получаю не могу вызвать "anotherServiceMethod" для нулевого объекта. Есть ли способ проверить этот тип контроллера? и это хороший подход для внедрения службы в другой сервис?

1 ответ

Решение

Это хороший подход, чтобы внедрить службу в другой сервис, в этом нет ничего плохого.

Чтобы этот тест работал, есть несколько подходов.

Рекомендуется - модульное тестирование должно проверять поведение только одного класса, если вам нужно протестировать полную функциональность, лучше сделать это со спецификацией интеграции / функциональности. В таком случае вы выполняете методы вашего контроллера, но все остальные вызываемые классы являются ложными, для которых вы предсказываете, какие значения возвращаются. Затем вы создаете отдельные тесты для MyService и AnotherService. В таком случае ваш тест может выглядеть так:

@TestFor(MyController)
class MyControllerSpec extends Specification {
    void "test something"(){
        given:
            MyService myService = Mock()
            controller.myService = myService
        when:
            controller.method1();
        then:
            1 * myService.serviceMethod() >> someResult
            //something
    }
}

этот тест гарантирует, что serviceMethod() вызывается, и вы заставляете его возвращать то, что вы ожидаете от этой спецификации. Если в другом случае (исключение выдается, если / иначе вы хотите быть уверены, что serviceMethod() не вызывается, вы можете использовать 0 * myService.serviceMethod()

Не рекомендуется: если вы настаиваете на том, что сервисный метод должен быть вызван в этой спецификации, вы можете создать макет AnotherService и установите его на службе, которая доступна в контроллере. Что-то вроде:

AnotherService anotherService = Mock()
controller.myService.anotherService = anotherService
...
then:
1 * anotherService.callAnotherMethod()

Может быть, также с помощью @Mock([MyService, AnotherService]) будет работать, но я не проверял это. Мы тестируем интеграцию с интеграционными тестами - там все для вас вводится и вы работаете на обычных классах.

Другие вопросы по тегам