0

I'm trying to unit test a service method that ultimately makes a call to the Criteria API's distinct(Collection) method (i.e., it calls the version of distinct() that takes a Collection). I'm getting the following error:

No signature of method: greenfield224.BookService.distinct() is applicable for argument types: (java.util.ArrayList) values: [[id, author, title, publisher]]

If I change the service method such that it uses the version of distinct() that accepts a single String property name, I do not get an error. But if that single property name is 'id', it returns nothing in the unit test.

I'm wondering if this is a bug in the Grails 2.2.4 test framework, or if I'm just not understanding something. Maybe using the distinct() method is not supported for unit tests? (An equivalent integration test works fine, by the way). Here is some example code that demonstrates the problem:

class Book {
    Long id
    String subject
    String author
    String publisher
    String title

    static constraints = {
        subject nullable: true
        author nullable: true
        publisher nullable: true
        title nullable: true
    }
}

class BookService {

    def findSimilarBooks(Book book) {
        def results = Book.withCriteria {
            eq('subject', book.subject)
            order('title')
            order('author')

            projections {
                //this line blows up in a unit test
                distinct(['id', 'author', 'title', 'publisher'])
            }
        }

        return results.collect {
            [id:it[0], author:it[1], title:it[2], publisher:it[3]]
        }
    }
}

@TestFor(BookService)
@Mock(Book)
class BookServiceSpec extends Specification {

    def "findSimilarBooks works properly"() {
        setup:
        def math = new Book(id:1, title:"Mathematics for Nonmathematicians", subject: "Math", author:"Morris Kline", publisher:"Somehouse")
        def philosophy = new Book(id:2, title:"The Problems of Philosophy", subject: "Philosophy", author:"Bertrand Russell", publisher:"Ye Olde House of Mutton")
        def investing = new Book(id:3, title:"The Intelligent Investor", subject: "investing", author:"Ben Graham", publisher:"Investors Anonymous")
        def qed = new Book(id:4, title:"Q.E.D.", subject: "Math", author:"Burkard Polster", publisher: "Wooden Books")
        def books = [math, philosophy, investing, qed]
        books*.save(failOnError: true)

        when:
        def results = service.findSimilarBooks(math)

        then:
        results.size() == 2
    }
}
Shawn Flahave
  • 501
  • 4
  • 13
  • 1
    Refer this [answer](http://stackoverflow.com/a/5239916/2051952). You should not be testing persistence in unit tests. Unit testing environment is [deprived of the persistence surrounding](http://grails.org/doc/latest/guide/testing.html#unitTesting). – dmahapatro Oct 17 '13 at 03:24
  • Thanks - yeah that makes sense. But if I accept the argument that you should not attempt to unit test code that issues a criteria query, then I'm not sure how to interpret the following statement from the Grails 2 docs: "A new in-memory GORM implementation is present that supports many more features of the GORM API making unit testing of criteria queries, named queries and other previously unsupported methods possible." – Shawn Flahave Oct 17 '13 at 11:55
  • 1
    It seems like it may be a bug in the in-memory GORM implementation. In general it looks like you are testing the logic of find similar books which mostly depends on the criteria I personally would do that as an integration test depending on H2 if you don't want to have your real DB server be part of the test. – Jeff Beck Oct 17 '13 at 14:59

0 Answers0