3

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

这是控制器的方法:

class MyController {
  MyService myService

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

这是我实现集成测试的方式:

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()
  }

PS 我在 STS 2.9.2 中使用 grails 2.0.0

4

2 回答 2

7

首先,我推荐使用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'
    }
}

如果您更喜欢不使用 Spock,对于 mock,您需要最简单的方法是使用Groovy coercion。看一下这个:

MyService mockService = [find: { String s -> [] }] as MyService

这是地图强制。在您模拟单个方法的情况下,甚至不需要 Map ,因此您可以更简单地编写它。

MyService mockService = { String s -> [] } as MyService

这就是闭包强制。好吧,指定参数也不是必需的,因为您没有处理它。

MyService mockService = { [] } as MyService

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

越简单越好,加油!

顺便说一句,在使用 Spock 时,您仍然可以使用强制模拟。Spock 模拟(使用 Mock() 方法创建)对于测试更高级的案例很有用,例如交互。

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

于 2012-12-20T17:28:00.017 回答
1

我建议您使用 Grails 注释来模拟您的服务,以下示例取自文档10.1 Unit Testing

@Mock([Book, Author, BookService])

然后测试控制器如下所示:

void testSearch() {
      def control = mockFor(SearchService)
      control.demand.searchWeb { String q -> ['mock results'] }
      control.demand.static.logResults { List results ->  }
      controller.searchService = control.createMock()
      controller.search()      assert controller.response.text.contains "Found 1 results"
}
于 2012-12-20T15:08:56.243 回答