2013-03-21 48 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