测试失败域的Grails在服务中保存

时间:2016-01-29 13:30:06

标签: unit-testing grails spock

我是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 对象,甚至在方法执行后使其无效。

但问题是:" 有没有办法像那样测试服务代码"

2 个答案:

答案 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并在那里强制失败。