我是Grails(3+)服务,其中从数据库检索域对象,修改,然后在数据库中更新。
class MyService {
def modifyObject(String uuid) {
def md = MyDomain.findByUuid(uuid)
md.someField = true
if (!md.save()){
throw new MyException()
}
}
}
现在我需要使用否定测试测试此服务方法,以确保抛出异常。但我无法弄清楚如何在服务方法中强制失败的save
。
@TestFor(MyService)
@Mock(MyDomain)
class MyServiceSpec extends Specification {
void "test An exceptionl situation was found"() {
given: "An uuid"
def md = new MyDomain(uuid: "123")
md.save(failOnError: true)
when: "service is called"
service.modifyObject("123")
then: "An exception is thrown"
thrown MyException
}
}
显然,以更实用的方式重新定义服务方法(对象直接传递给方法,修改并返回而不保存 .eg MyDomain modifyObject(MyDomain md)
)将是一个很好的方法解决方案,因为我可以在方法外部创建一个无效的 ad hoc 对象,甚至在方法执行后使其无效。
但问题是:" 有没有办法像那样测试服务代码?"
答案 0 :(得分:0)
假设您确实想要抛出异常并且不仅仅处理验证错误,那么请确定。您将希望利用Spock对基于交互的测试的支持并利用静态方法存根。请参阅类似问题Unit test grails with domain objects using GORM functions。
您需要某种方法来隔离服务方法并存根GORM功能。使用静态方法这可能很棘手,但可以使用全局GroovyMock或GroovySpy来完成。本质上,您将在方法的持续时间内替换MyDomain
的所有实例/引用(尽管GroovySpy将回退到实际的域类,除非交互匹配)。
使用Mock / Spy,您可以指定预期发生的交互,并指定这些交互应返回的内容。在这种情况下,我们希望使用findByUuid
参数调用"123"
一次,然后返回模拟MyDomain
对象。那个模拟对象然后在我们返回null时调用它的save()
方法,即保存失败。
void "test An exceptional situation was found"() {
setup:
GroovySpy(MyDomain, global: true)
def mockDomain = Mock(MyDomain)
when: "service is called"
service.modifyObject("123")
then: "An exception is thrown"
1 * MyDomain.findByUuid("123") >> mockDomain
1 * mockDomain.save() >> null
thrown Exception
}
答案 1 :(得分:0)
如果您违反MyDomain上的约束并且保存失败,不是吗?
如果modifyObject真的很简单,并且你不能传入伪造的值来强制违反约束,那么你可能需要对MyDomain.save进行metaClass并在那里强制失败。