如何测试利用criteria查询的Grails Service(使用spock)?

11
我正在尝试测试一个简单的服务方法。该方法主要只返回条件查询的结果,我要测试它是否返回一个结果(根据查询内容而定)。
问题是,我不知道如何正确编写相应的测试。我正在尝试使用Spock完成,但使用任何其他测试方式也会失败。
请问有人能告诉我如何修改测试以使其适用于手头的任务吗?
(顺便说一句,如果可能,我想让它保持为单元测试。)
事件服务方法
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)
2个回答

17

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

相反,将条件查询移到域类中一个适当命名的方法并使用集成测试来针对数据库进行测试:

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 }

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


4

单元测试不支持条件查询。从mockDomain文档中可以看到:

[该插件]不支持模拟Criteria或HQL查询。如果您使用了它们中的任何一个,请手动模拟相应的方法(例如,使用mockFor())或使用带有真实数据的集成测试。

您需要将测试转换为集成测试。如果将测试从test/unit文件夹移动到test/integration文件夹,则会发现该异常消失了。

目前正在进行一些关于在单元测试中支持criteria的工作,如果你想尝试一下,可以参考这个DatastoreUnitTestMixin的邮件列表讨论


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接