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
}
}
我是使用 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
}
}