覆盖grails集成测试中的服务方法

Tom*_*ato 3 testing grails groovy integration-testing metaprogramming

我正在尝试测试控制器在集成测试中的操作.这是一个简单的场景,我正在尝试测试的操作是调用服务的方法.我试图使用元类覆盖该方法,但看起来它不起作用,即服务的实际方法总是被调用而不是我使用元类重写的那个.我在这做错了什么?

这是控制器的方法:

class MyController {
  MyService myService

  def methodA() {
    def u = myService.find(params.paramA)
    render view: "profile", model:  [viewed: u]
  }
Run Code Online (Sandbox Code Playgroud)

以下是我实现集成测试的方法:

class MyControllerTests extends GroovyTestCase {

 MyController controller

 void testMethodA() {
    controller = new MyController()

    // Mock the service
    MyService mockService = new MyService()
    mockService.getMetaClass().find = { String s ->
      []
    }

    controller = new MyController()
    controller.myService = myService

    controller.methodA()
  }
Run Code Online (Sandbox Code Playgroud)

PS我在STS 2.9.2中使用grails 2.0.0

top*_*opr 8

首先,我建议使用Spock Framework,这是一个非常好的测试库,除了与Grails很好地集成.您的测试将如下所示:

@TestFor(MyController) // TestFor is builtin Grails annotation
class MyControllerSpec extends Specification {

    // thanks to TestFor annotation you already have 'controller' variable in scope

    MyService mockService = Mock(MyService)

    // setup method is executed before each test method (known as feature method)
    def setup() {
        controller.myService = mockService
    }

    def 'short description of feature being tested'() {
        given:
        mockService.find(_) >> [] // this tells mock to return empty list for any parameter passed

        when:
        controller.methodA()

        then:
        // here goes boolean statements (asserts), example:
        controller.response.text.contains 'Found no results'
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你喜欢不使用Spock,那么对于模拟你需要最简单的方法就是使用Groovy强制.看一下这个:

MyService mockService = [find: { String s -> [] }] as MyService
Run Code Online (Sandbox Code Playgroud)

这是地图强制.在你的情况下,当模拟单个方法时,甚至不需要Map,所以你可以更简单地编写它.

MyService mockService = { String s -> [] } as MyService
Run Code Online (Sandbox Code Playgroud)

这是封闭强制.好吧,既不需要指定参数,也不需要处理它.

MyService mockService = { [] } as MyService
Run Code Online (Sandbox Code Playgroud)

最后一个语句基本上意味着在mockService上调用的任何方法将执行指定的闭包,因此将在结果中返回空列表.

更简单更好,欢呼!

顺便说一下,当使用Spock时,你仍然可以使用强制模拟.Spock模拟(使用Mock()方法创建)对于测试更高级的案例非常有用,例如交互.

更新:对于集成测试,您将扩展IntegrationSpec,并且不需要使用@TestFor.