如何使用注入了其他服务的服务来测试 grails 3 控制器?

how to test grails 3 controller with services that have another services inject into them?

在控制器的单元测试用例中,我只能注入相应 controller.But 中使用的服务,如果说控制器中的一个服务注入了另一个服务,那么我的测试用例就会失败,即无法调用空对象上的服务方法。

@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"。 有什么方法可以测试这种类型的控制器吗?在另一个服务中注入服务是一种好方法吗?

将服务注入另一个服务是一种很好的方法,这没有错。

要使此测试有效,有几种方法。

推荐 - 单元测试应该只测试单个 class 的行为,如果您需要测试全部功能,integration/functional 规范更适合这样做。在这种情况下,您执行控制器的方法,但所有其他被调用的 classes 都是模拟,您可以预测哪些值是 returned。然后为 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() 并且您强制它 return 满足您对该规范的期望。如果在其他情况下(抛出异常,if/else 你想确保 serviceMethod() 没有被调用,你可以使用 0 * myService.serviceMethod()

不推荐:如果您坚持在本规范中调用服务方法,您可以创建 AnotherService 的模拟并将其设置在控制器中可用的服务上。类似于:

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

也许也可以使用 @Mock([MyService, AnotherService]),但我没有测试过。我们通过集成测试来测试集成 - 一切都为您注入,您可以正常工作 classes.