Grails Spock 模拟对象

Grails Spock Mocking an Object

我是使用 Spock 在 Grails 应用程序中进行单元测试的新手。但是我想问以下问题。假设我想 运行 测试以下函数 testfun。

class TestFun{

boolean testfun(long userId, long orderId){

    User user = User.findByUserId(userId)
    if(user == null)return false
    Order order = Order.findByUserAndId(user, orderId)

    HashMap<String, Object> = orderContent   
    orderContent= order.orderContent // the order has an element orderContent for storing the elements that one user orders

    if(orderContent!=null){
      orderContent.put("meal",1)
      order.orderContent = orderContent
      return true
    }

    return false
}
}

在这种情况下相应的单元测试将是:

class TestFun extends Specification {

    def setup() {

        GroovySpy(User, global: true)
        GroovySpy(Order, global: true)
    }
 def "test funtest"() {

        User user = new User(2).save()
        Order order = new Order(3).save()

        when:
        service.testfun(2,3) == result

        then:
        2*User.findByUserId(2) >> Mock(User)
        1*Order.findByUserAndId(_ as User, 1)>> Mock(Order)
        result == true
}
}

但是,我认为我必须模拟 order.orderContent 但我不知道如何模拟它。现在测试失败了,因为 orderContent 是 null 所以 testfun returns false.

谁能帮我解决这个问题?

这里发生了几件事,希望解决这些问题能帮助您通过考试 运行 并通过。

我记不清了,但我相信 GroovySpy 是一个旧功能,没有用于 Spock 测试。与其使用它来模拟域 class,不如在 class 定义之前使用 @Mock 注释来指定要模拟的域 classes。

虽然您可以模拟域 classes,但您还需要使用这些对象实际填充内存数据库,可以在 setup: 块中,也可以在 setup() 方法,如果它们需要用于多个测试。

您提到创建模拟,使用 Spock Mock() 方法将创建该对象的模拟,但您不想将其用于域对象。它通常用于服务 classes 将被手动注入到您的测试 class.

保存模拟域 class 时,我建议包括参数 flush: true, failOnError: true,这样任何失败的验证都会立即显示在适当的行上。否则,您可能会在稍后的测试中出现一些奇怪的错误。

我不知道你在 when: 块中做什么,但你不应该在那个时候用 == 做断言,做所有那些在 then:块。

考虑到所有这些,我认为您的测试 class 应该看起来更像这样:

@Mock([User, Order])
class TestFun extends Specification {

    def setup() {
        // This object will have an id of 1, if you want a different id, you can either specify it, or create more objects
        User user = new User(first: "john", last: "doe").save(flush: true, failOnError: true)
        new Order(user: user).save(flush: true, failOnError: true)
    }

    def "test funtest"() {

        User user = new User(2).save()
        Order order = new Order(3).save()

        when:
        boolean result = service.testfun(1, 1)

        then:
        // Optionally you can just use "result" on the next line, as true will be assumed
        result == true
    }
}