【问题标题】:How to mock a service in an integration test for a dynamically scaffolded Grails controller?如何在动态脚手架 Grails 控制器的集成测试中模拟服务?
【发布时间】:2013-02-10 13:31:03
【问题描述】:

我正在尝试在动态脚手架控制器的集成测试中模拟服务。我收到一条错误消息,表明无法从测试中访问服务的控制器属性。

似乎根本无法使用单元测试来测试动态脚手架控制器,所以我正在使用集成测试。我想模拟该服务以测试我的应用程序中的错误处理。这是 Grails 2.2.0 中的错误还是我做错了?

grails test-app 的结果是:

groovy.lang.MissingPropertyException: No such property: myService for class: MyController

例子:

我修改了src/templates/scaffolding/Controller.groovy:

class ${className}Controller {
  MyService myService

  def action() {
    render myService.serviceMethod()
  }
}

动态脚手架MyController.groovy:

class MyController {
    static scaffold = MyDomainClass
}

集成测试MyControllerTests.groovy

class MyControllerTests extends GroovyTestCase {
  def myController

  @Before
  void setUp() {
    myController = new MyController()
  }

  void testMock() {
    myController.myService = [ serviceMethod : { return "foo" } ] as MyService
    controller.action()
  }
}

【问题讨论】:

    标签: unit-testing grails mocking


    【解决方案1】:

    尝试使用setter方法:

    void testMock() {
        myController.setMyService([ serviceMethod : { return "foo" } ])
        controller.action()
    }
    

    如果你执行:println c.metaClass.methods*.name,你会看到有getSetMyService()和getGetMyService()这样的方法。我不确定,但可能 Grails 没有添加字段,而是为字段 get/set 方法添加 getter。

    【讨论】:

    • 谢谢! controller.setXxxService() 方法成功了!不过,作为参数的 Map 需要进行类型转换:controller.setMyService([...] as MyService)。此外,您需要将服务重置为真实服务以进行下一次测试。设置后,Grails 似乎会保留模拟。我将在下面的另一个答案中展示一个示例实现。
    【解决方案2】:

    集成测试应按如下所示实施。如果我们在测试中模拟服务,我们必须自己重置它。 Grails 不会为我们做这件事,这很神秘,因为控制器是在 setUp() 中创建的。

    droggo 上面的回答揭示了在 SUT 中注入模拟的正确方法。我还将添加一个使用 Groovy 模拟的示例。不过它有点冗长。

    class MyControllerTests extends GroovyTestCase {
      def myController
      def myService
    
      @Before
      void setUp() {
        myController = new MyController()
      }
    
      @After
      void tearDown() {
        myController.setMyService(myService)
      }
    
      void testMapMock() {
        myController.setMyService([ serviceMethod : { return "foo" } ] as MyService)
        controller.action()
      }
    
      void testGroovyMock() {
        def myServiceMockContext = new StubFor(MyService)
        myServiceMockContext.demand.serviceMethod() { -> return "bar" }
        def myService = myServiceMockContext.proxyInstance()
        controller.setMyService(myService)
        controller.action()
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-09
      • 1970-01-01
      • 2014-09-01
      • 2023-04-04
      • 1970-01-01
      相关资源
      最近更新 更多