使用GORM函数对域对象进行单元测试

时间:2016-01-26 15:49:31

标签: unit-testing grails groovy

我在Grails上的Groovy中名为OrderService的服务类中有以下代码。我想为这堂课做一个单元考试。用户和订单属于域类。用户有很多订单。

boolean testfun(long userId, lond orderId){

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

        return true
    }

我要编写的单元测试如下(使用Spock):

@TestFor(OrderService)
@Mock([User, Order])
class OrderServiceSpec extends Specification{
 def "test funtest"() {

        User user = new User(2)
        Order order = new Order()
        order.metaClass.id = 3// I want to assign the id of the order in domain  
        order.save()        
        user.addToOrders(order)
        user.save()

        expect:
        service.testfun(2,3) == true
}
}

但是此测试失败,因为订单为空。谁能帮我? 另一个问题是:这个测试是单元测试吗?或者我应该用grails编写集成测试?

1 个答案:

答案 0 :(得分:3)

这取决于你实际尝试测试的内容,但这可以是一个单元测试 - 我只是建议稍微修改它以隔离你感兴趣的测试服务方法。您根本不打算测试域类,因此最好模拟/存储您需要的行为来测试服务功能。

这样做的好方法是Spock通过模拟对象支持interaction based testing。基本上我们指定在调用服务的testfun()方法时,我们希望调用User.findById()一次,并且Order.findByUserAndId()也被调用一次。 Spock然后允许我们对每个方法调用进行存根,以便指定我们希望方法返回的内容。当我们运行测试时,将使用存根,而不是实际的GORM方法。

一些复杂性在于剔除静态方法(如GORM方法),但您可以使用GroovySpy来完成工作。

另外,我假设您打算使用User.findById()代替User.findByUserId()

这些方面的内容对您有用:

def "test funtest"() {
    setup:
    // Global so that it replaces all instances/references of the
    // mocked type for the duration of the feature method.
    GroovySpy(User, global: true)
    GroovySpy(Order, global: true)

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

    then:
    // No need to return real objects, so use a mock
    1 * User.findById(2) >> Mock(User)
    1 * Order.findByUserAndId(_ as User, 3) >> Mock(Order)
    result == true

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

    then:
    1 * User.findById(2) >> null
    result == false
}

请注意,我们已经隔离了服务方法。任何协作对象(用户和订单)只与via stub交互,我们可以测试服务方法的功能,而不必担心GORM。