2012-12-20 44 views
3

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

这里是控制器的方法:

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

附:我使用的Grails 2.0.0在STS 2.9.2

回答

7

首先关闭所有我推荐使用Spock Framework这是非常好的一件测试库,除了integrates with Grails pretty well。 那么您的测试看起来像:

@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' 
    } 
} 

如果您希望继续留在不使用斯波克,用于模拟你需要的最简单的方法将使用Groovy的强制。检查了这一点:

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

这是地图胁迫。在你的情况下,当嘲笑单一的方法,甚至不需要地图,所以你可以写得更简单。

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

这是封强制。那么,指定参数不是必要的,因为你没有处理它。

MyService mockService = { [] } as MyService 

最后一条语句基本上意味着比呼吁mockService将执行指定闭合的任何方法,所以空单将在结果中返回。

简单更好,欢呼!

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

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

+1

topr,非常感谢!我最终使用了你建议的强制技术,并且一切正常。 – Tomato

+1

是不是集成测试的问题?它看起来像代码是单元测试。 –

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" 
} 
相关问题