2013-03-21 52 views
8

對不起,如果這是一個新手問題,但我真的很感謝社區可以提供的任何見解,關於我遇到的一個問題,在Grails服務中,LocationService。使用Spock將Grails和其他方法都存放在Grails域的類中

Location locate(String target, String locator, Application app, boolean sync = true) { 
    if (!target) throw new IllegalArgumentException("Illegal value for msid: " + target) 
    def locRequest = Request.create(target, Type.LOCATE) 
    if (!locRequest.save()) { 
      return Location.error(target, "Error persisting location request") 
    } 
    locationSource.locateTarget(target, locator, app, sync) 
} 

我有一個域類,Request,以及默認的GORM方法也有一些額外的域方法,例如。下面的create()方法

@EqualsAndHashCode 
class Request { 

    String reference 
    String msid 
    Type type 
    Status status 
    Destination destination 
    DateTime dateCreated 
    DateTime dateCompleted 

    static create(String msid, Type type, Destination destination = Destination.DEFAULT) { 
      new Request(reference: reference(type), type: type, status: Status.INITIATED, dateCreated: new DateTime()) 
    } 

最後,我有一個Spock規範。我需要嘲笑默認的GORM方法,但也需要存儲一些額外的領域邏輯,例如靜態創建方法,以便返回一個有效的對象以在測試中的代碼中持久化。

理想情況下,我會使用Spock mock,但我不能在這裏使用它們,因爲根據Peter N的帖子,他們需要注入調用者,在這種情況下請求(我試圖模擬),被創建爲在LocationService在定位方法的局部變量:

https://groups.google.com/forum/?fromgroups=#!topic/spockframework/JemiKvUiBdo

我也不能使用Grails 2.x的@Mock註釋如,儘管這將嘲笑GORM方法,我不能確定是否我可以從Request類中模擬/存儲額外的靜態create()方法。因此,最後,我一直在嘗試使用Groovy StubFor/MockFor方法來做到這一點,因爲我相信通過將它們封裝在使用閉包中(如下所示),這些將用於對測試方法的調用。

下面是測試規範:

@TestFor(LocationService) 
// @Mock(Request) 
class LocationServiceSpec extends Specification { 

    @Shared app = "TEST_APP" 
    @Shared target = "123" 
    @Shared locator = "999" 

    def locationService = new LocationService() 
    LocationSource locationSource = Mock() 


    def "locating a valid target should default to locating a target synchronously"() { 
     given: 
      def stub = new StubFor(Request) 
      stub.demand.create { target, type -> new Request(msid: target, type: type) } 
      stub.demand.save { true } 
      1 * locationSource.locateTarget(target, locator, app, SYNC) >> { Location.create(target, point, cellId, lac) } 
      def location 
     when: 
      stub.use { 
       location = locationService.locate(target, locator, app) 
      } 
     then: 
      location 
} 

然而,當我運行測試,雖然存根創建方法返回我的要求存根對象,我得到一個失敗的存根保存方法:

groovy.lang.MissingMethodException: No signature of method:  com.domain.Request.save() is applicable for argument types:() values: [] 
Possible solutions: save(), save(boolean), save(java.util.Map), wait(), last(), any() 

有沒有人請指出我在做什麼錯在這裏或建議最好的方法來解決我的具體情況,如果需要存根其他方法以及域類的GORM方法,我不能直接注入代碼下測試?

謝謝你在前進,

帕特里克

回答

8

我相信你應該能夠像你這樣的GORM方法提及使用Grails的@Mock註釋,然後你將需要手動嘲笑靜態方法:

@TestFor(LocationService) 
@Mock(Request)// This will mock the GORM methods, as you suggested 
class LocationServiceSpec extends Specification { 
... 
    void setup() { 
     Request.metaClass.static.create = { String msid, Type type, Destination destination = Destination.DEFAULT -> 
      //Some logic here 
     } 
    } 
... 

當使用@Mock註釋,Grails將嘲笑默認的方法(保存/獲取/動態查找器),但它不會對你做什麼可能已添加任何附加的方法,所以你需要爲MANU盟友嘲笑那些。

+0

謝謝GrailsGuy。這解決了我的問題。我在使用'@ Mock'來模擬默認方法以及如何手動覆蓋其他方法之間陷入了混亂。使用'@ Mock'給了我前者,而不是後者。使用StubFor給了我後者,但不是前者。但他們似乎並沒有合作。然而,對前者使用'@ Mock'並修改metaClass以獲得後者可以很好地解決問題。非常感謝。 – Paddy 2013-03-21 14:38:36

+1

@Paddy沒問題,很高興能幫到你! – Igor 2013-03-21 14:41:19

+1

@Igor它應該是「Request.metaClass.static.create ...」這就是我的工作! – Champ 2014-09-17 11:24:35