2012-12-20 45 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" 
} 
相關問題