【问题标题】:Using Spock to stub both Gorm and other methods in a Grails domain class使用 Spock 存根 Grails 域类中的 Gorm 和其他方法
【发布时间】:2013-03-10 19:03:35
【问题描述】:

很抱歉,如果这是一个新手问题,但我非常感谢社区可以就我在使用 Grails 服务 LocationService 中的以下方法存根时遇到的问题提供任何见解。

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 模拟,但根据 Peter N 下面的帖子,我不能在这里使用它们,它们需要注入到调用者中,在这种情况下是请求(我试图模拟) , 在 LocationService 的 locate 方法中创建为局部变量:

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

我也不能使用 Grails 2.x @Mock 注释,因为虽然这会模拟 GORM 方法,但我不确定我是否可以模拟/存根来自 Request 类的附加静态 create() 方法。

因此,最后,我一直在尝试使用 Groovy StubFor / MockFor 方法来执行此操作,因为我相信这些将通过将测试方法包装在 use 闭包中来用于调用测试方法(如下所示)。

这是测试规范:

@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 方法,谁能指出我在这里做错了什么或建议解决我的特殊情况的最佳方法测试?

提前谢谢你,

帕特里克

【问题讨论】:

    标签: grails mocking grails-orm stub spock


    【解决方案1】:

    我相信您应该能够使用 Grails 的 @Mock 注释,就像您提到的 GORM 方法一样,然后您需要手动模拟静态方法:

    @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 将模拟默认方法(save/get/dynamic finders),但它不会对您可能添加的任何其他方法执行任何操作,因此您需要手动模拟这些方法。

    【讨论】:

    • 谢谢 GrailsGuy。这解决了我的问题。我在使用@Mock 模拟默认方法和如何手动覆盖其他方法之间陷入了纠结。使用@Mock 给了我前者但不是后者。并且使用 StubFor 给了我后者但不是前者。但它们似乎并没有协同工作。但是,前者使用@Mock,修改metaClass得到后者,就完美解决了这个问题。非常感谢。
    • @Paddy 没问题,很高兴我能帮上忙!
    • @Igor 应该是“Request.metaClass.static.create...” 这对我有用!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-16
    • 1970-01-01
    • 2018-11-16
    • 2012-08-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多