How to test a grails Criteria query?
Asked Answered
F

3

7

first post here and hopefully relevant to many people.

I'm working on writing integration tests for a domain and on that domain I have a query using the withCriteria() method. I've searched all over the net and found many that give you detailed instructions on how to go about mocking a criteria query, but none on how to exactly test it.

I've tried mocking the domain using the mockDomain(domain,list) function, and setting up a domain for the test to use in the setUp() then calling the criteria and I get nothing. I did a similar findBy here and got the results, but not exactly the ones I was looking for. I'm pretty sure it's not just my query, but the criteria, I've read in a few places criteria does not work in service testing. The query thus far has worked for me in the app, but I want to have some tests that I can refer to later in case my code base changes.

I've actually done as many have suggested and pulled out the code for the query and made it a static method in my domain so that I can mock it for the tests that use it, but now I'm stuck with how to actually test this part. Do I need to run the app and just do functional testing from that standpoint, or is there some way I could do this in the grails unit/integration testing. I'll post my query below.

static Attribute getDefinitionsUsingCriteria(List categoryNames, List types){
        def definitions = Definition.withCriteria() {
            and {
                'in'('type', types)
                if (categoryNames) {
                    categories {
                        'in'('name', categoryNames)
                    }
                }
            }
        }
        return definitions
    }

Definitions has a string property type, and has a property categories of type Set that each element in this set has a String name property.

I'm still pretty new to grails and have been reading many reference books, and I'm surprised this is missing in all of the books I've read thus far. I hope this is something that is just a mistake on my part, and easily testable. I appreciate any help, and thanks for reading this long post.

JR.

Fame answered 3/6, 2011 at 21:36 Comment(0)
L
7

One way: move the test from test/unit to test/integration folder. Criteria won't work in unit test (there's no Hibernate there), but will in integration. Never use mockDomain() in integration tests.

Note: don't make the method static - it only complicates testing.

Second way: In unit tests - use mockDomain(). Just rely on the fact that the logic is pretty straightforward, and unit-test everything except the method. Override it in setUp() like:

Definition.metaClass.getDefinitionsUsingCriteria = { List categoryNames, List types ->
    delegate.findAll{ (it.type in types) && 
        (it.categories.find { c -> c in categoryNames }) 
    }
}
Limulus answered 3/6, 2011 at 21:46 Comment(7)
I agree - don't unit test persistence, you're just testing the mocking framework. Test persistence using integration tests with a database, either the default in-memory database or a 'real' one.Scissure
Hey Victor, I do have it in the test/integration folder. I originally had the query in a service file, but wasn't getting the list results I expected from the tests,.. They all came back as empty lists. I shall however try again and remove the static. I did however finish all the testing and I guess for the moment I'll go with the second way. Thanks for the help, I really appreciate it.Fame
Then, absolutely, the query must work. Do you have any data in the database at that point? What if you try calling Definition.list() or the criteria code itself in grails console?Limulus
I assume I have the data correctly in the database. I'm using the mockDomain() method to do so. As in, mockDomain(Definition,[new Defintion(ownerType:"type1")]) for a simple one and that seems to work for the Definition.list(). For my testing, when I do Definition.list() I get back the whole mockedDomain I made for that method. I can also do Definition.findByOwnerType() just fine too, but the query itself is the only thing not working. I'm trying out this grails console as I type this and will get back to you. THanks for the help. :)Fame
Wait! The reason is opposite to what I was thinking %) You don't need mockDomain() in integration tests, it is actually harmful - mockDomain() only replaces a dynamic GORM methods that GORM already created in integration test environment. That's why it's not working - all the objects are save()d to the List parameter of mockDomain() and never hit the HSQL database. The Criteria is the only method that queries HSQL, which is empty. In short, remove all mockDomain()s. Or, better, move the test to unit tests and test it there - it's a better style.Limulus
K, that makes sense, thanks for explaining that. For future reference, would I use just the save() method to put things into the HSQL database for integration testing? Moving it over to a unit test worked! Thanks again for being very helpful,.. I've been waiting about 2 weeks on the grails user forums...Fame
Absolutely. In integration tests, nearly the whole application is initialized - except for the presentation layer. So save() will work, like everything else.Limulus
W
3

Grails 2.0.1 now has native @Mock for test criteria, but groupProperty is not implemented yet.

I wrote mock criteria plugin (with groupProperty)

https://github.com/fabiooshiro/plastic-criteria

it works in 1.3.7

Weatherbeaten answered 7/3, 2012 at 4:47 Comment(1)
Thanks for the plugin. It is the exact thing I have been looking for.Sternpost
E
0

Criteria are supported since grails 2.2. See "Unit Testing GORM" at What's new in Grails 2.2

Eaglestone answered 15/8, 2013 at 17:19 Comment(1)
Yes..but some projections are not supported, like groupProperty (as @Sr. Oshiro said)Sternpost

© 2022 - 2024 — McMap. All rights reserved.