开发者

How to test a Grails Service that utilizes a criteria query (with spock)?

I am trying to test a simple service method. That method mainly just returns the results of a criteria query for which I want to test if it returns the one result or not (depending on what is queried for).

The problem is, that I am unaware of how to right the corresponding test correctly. I am trying to ac开发者_高级运维complish it via spock, but doing the same with any other way of testing also fails.

Can one tell me how to amend the test in order to make it work for the task at hand?

(BTW I'd like to keep it a unit test, if possible.)

The EventService Method

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
}

The Spock Specification

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
    }
}

The Error

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)


You should not use unit tests to test persistence - you're just testing the mocking framework.

Instead, move the criteria query to an appropriately named method in the domain class and test it against a database with an integration test:

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)
   }
}

If there's still value in having the service method as a wrapper (e.g. if it implements some business logic above and beyond the database query), it will now be easy to unit test since it's trivial to mock out the static domain class method call:

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

And that's appropriate since you're testing how the service uses the data it receives and assuming that the retrieval is covered in the integration tests.


Criteria queries are not supported in unit tests. From the mockDomain documentation:

[T]he plugin does not support the mocking of criteria or HQL queries. If you use either of those, simply mock the corresponding methods manually (for example with mockFor() ) or use an integration test with real data.

You'll have to make your test an integration test. You'll see that the exception goes away if you move the test from the test/unit folder to the test/integration folder.

There is some work being done on criteria support in unit tests, and if you're feeling adventurous, you can try it out today. See this mailing list discussion of the DatastoreUnitTestMixin.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜