【问题标题】:How to test a Grails Service that utilizes a criteria query (with spock)?如何测试使用条件查询(使用 spock)的 Grails 服务?
【发布时间】:2011-07-11 00:14:53
【问题描述】:

我正在尝试测试一个简单的服务方法。该方法主要只返回一个条件查询的结果,我想测试它是否返回一个结果(取决于查询的内容)。

问题是,我不知道如何正确正确地进行相应的测试。我试图通过 spock 来完成它,但是用任何其他测试方式做同样的事情也会失败。

谁能告诉我如何修改测试以使其适用于手头的任务?

(顺便说一句,如果可能的话,我希望将其保留为单元测试。)

EventService 方法

public HashSet<Event> listEventsForDate(Date date, int offset, int max) {
    date.clearTime()

    def c = Event.createCriteria()
    def results = c {
        and {
            le("startDate", date+1) // starts tonight at midnight or prior?
            ge("endDate", date)     // ends today or later?
        }
        maxResults(max)
        order("startDate", "desc")
    }
    return results
}

Spock 规范

package myapp

import grails.plugin.spock.*
import spock.lang.*

class EventServiceSpec extends Specification {

    def event
    def eventService = new EventService()

    def setup() {
        event = new Event()

        event.publisher = Mock(User)
        event.title     = 'et'
        event.urlTitle  = 'ut'
        event.details   = 'details'
        event.location  = 'location'
        event.startDate = new Date(2010,11,20, 9, 0)
        event.endDate   = new Date(2011, 3, 7,18, 0)
    }

    def "list the Events of a specific date"() {
        given: "An event ranging over multiple days"

        when: "I look up a date for its respective events"
        def results = eventService.listEventsForDate(searchDate, 0, 100)

        then: "The event is found or not - depending on the requested date"
        numberOfResults == results.size()

        where:
        searchDate              | numberOfResults
        new Date(2010,10,19)    | 0     // one day before startDate
        new Date(2010,10,20)    | 1     // at startDate
        new Date(2010,10,21)    | 1     // one day after startDate
        new Date(2011, 1, 1)    | 1     // someday during the event range
        new Date(2011, 3, 6)    | 1     // one day before endDate
        new Date(2011, 3, 7)    | 1     // at endDate
        new Date(2011, 3, 8)    | 0     // one day after endDate
    }
}

错误

groovy.lang.MissingMethodException: No signature of method: static myapp.Event.createCriteria() is applicable for argument types: () values: []
    at myapp.EventService.listEventsForDate(EventService.groovy:47)
    at myapp.EventServiceSpec.list the Events of a specific date(EventServiceSpec.groovy:29)

【问题讨论】:

    标签: unit-testing hibernate grails junit spock


    【解决方案1】:

    您不应该使用单元测试来测试持久性 - 您只是在测试模拟框架。

    相反,将条件查询移动到域类中适当命名的方法,并通过集成测试针对数据库对其进行测试:

    class Event {
       ...
       static Set<Event> findAllEventsByDay(Date date, int offset, int max) {
          ...
       }
    }
    
    class EventService {
    
       Set<Event> listEventsForDate(Date date, int offset, int max) {
          ...
          return Event.findAllEventsByDay(date, offset, max)
       }
    }
    

    如果将服务方法作为包装器仍然有价值(例如,如果它在数据库查询之外实现一些业务逻辑),那么现在将很容易进行单元测试,因为模拟静态域类方法很简单调用:

    def events = [new Event(...), new Event(...), ...]
    Event.metaClass.static.findAllEventsByDay = { Date d, int offset, int max -> events }
    

    这是合适的,因为您正在测试服务如何使用它接收到的数据并假设检索已包含在集成测试中。

    【讨论】:

      【解决方案2】:

      单元测试不支持条件查询。来自mockDomain documentation

      [T]该插件不支持模拟标准或 HQL 查询。如果您使用其中任何一种,只需手动模拟相应的方法(例如使用 mockFor() )或使用真实数据的集成测试。

      您必须使您的测试成为集成测试。如果您将测试从 test/unit 文件夹移动到 test/integration 文件夹,您会看到异常消失。

      在单元测试中的标准支持方面正在做一些工作,如果您喜欢冒险,今天就可以尝试一下。看到这个mailing list discussion of the DatastoreUnitTestMixin

      【讨论】:

        猜你喜欢
        • 2013-09-09
        • 2012-03-29
        • 1970-01-01
        • 2016-06-17
        • 1970-01-01
        • 2016-06-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多