Extending Grails mocking for unit tests (createCriteria, withNewSession, etc...) - unit-testing

As part of a Grails project, I'm currently extending my test suite to stuff that need a complete environment to run, like for instance custom HQL and criteria queries, session related issues, etc. I'm using integration tests.
We already have a fairly large number of unit tests (> 500), where we used to mock methods that don't have a Grails mocked counterpart by default (like withCriteria, withNewSession, etc.) using helper functions like this one:
static mockCriteria(Class clazz, returnValue)
{
def myCriteria = new Expando()
myCriteria.list = {Closure cls -> returnValue}
myCriteria.get = {Closure cls -> returnValue}
clazz.metaClass.static.createCriteria = { -> myCriteria }
}
Code could then be tested like this:
mockCriteria(MyClass, [result])
assert myClass.createCriteria.list({ ... }) == [result]
Until now I always managed to meet my needs using this approach.
Now I want to add integration tests that actually check how methods that use criterias and HQL queries behave, in order to facilitate refactoring these queries. I'm stuck by the fact that createCriteria is replaced in my tests and don't recover their initial code after the unit tests phase, preventing me from testing them in the integration phase.
How do you address the problem of mocking criteria (or HQL queries, etc.), while allowing to get the original behavior back in integration tests?
EDIT: Unfortunately, upgrading to Grails 2 is not an option.

I rather mock not criterias, but domain methods that use them.
Plus, Grails 2.0 promise to have criteria support in unit tests - not HQL, though.

Try this:
void setUp() {
super.setUp()
registerMetaClass MyClass
}
Under the Hood
def a = [1, 2, 3]
def oldMetaClass = ArrayList.metaClass
ArrayList.metaClass.find = { Closure cls -> 5 }
assert 5 == a.find{ it == 1}
ArrayList.metaClass = oldMetaClass
assert 1 == a.find{ it == 1 }
​
And for mockCriteria take a look
https://github.com/fabiooshiro/plastic-criteria
(works with 1.3.7)

Related

how to mock/stub out a specific custom validator when doing unit testing in grails?

Lets say i have a domain A which has a custom validator for property P
static constraints = {
P validator: { val, obj ->
(A.executeQuery("SELECT COUNT(*) FROM A cei WHERE cei.event.id = ?", [val.id])[0] <= 1)
}
In the unit test how can i mock the P property of domain A so that i don't get the error i am getting when running unit test. The error i get when running unit test is shown below. The setup code instantiates domain A as shown below.
void setUp(){
inv = new A(P: rg).save(flush: true)
Error is
java.lang.UnsupportedOperationException: String-based queries like [executeQuery] are currently not supported in this implementation of GORM. Use criteria instead.
Note: These are fake code.
The best option for me, is encapsulate the inner code of the validator inside a service. And then, mock that service in your unit test.
But the error thrown is that executeQuery is not available, but criteria is.
So change your code for using a criteria instead.
P validator: { val, obj ->
A.withCriteria{
eq('event', Event.findById(val.id))
projections{
count('id')
}
}[0] < = 1
}

Unit test grails with domain objects using GORM functions

I have the following piece of code inside a service class named OrderService in Groovy on Grails. I want to make a unit test for this class. User and Order are domain classed. A user has many orders.
boolean testfun(long userId, lond orderId){
User user = User.findByUserId(userId)
if(user == null)return false
Order order = Order.findByUserAndId(user, orderId)
if(order == null)return false
return true
}
The unit test that I am trying to write is the following (using Spock):
#TestFor(OrderService)
#Mock([User, Order])
class OrderServiceSpec extends Specification{
def "test funtest"() {
User user = new User(2)
Order order = new Order()
order.metaClass.id = 3// I want to assign the id of the order in domain
order.save()
user.addToOrders(order)
user.save()
expect:
service.testfun(2,3) == true
}
}
However this test fails because the order is null. Can anyone help me?
Another question is: is this test a unit test? or should I write an integration test in grails?
It depends on what you're actually trying to test, but this can be a unit test—I'd just recommend modifying it a little bit to isolate only the service method that you're interested in testing. You're not looking to test the domain classes at all, so it's best to mock/stub the behavior that you need from them to test the service functionality.
A good way to do this is with Spock's support for interaction based testing via mock objects. Basically we specify that when the service's testfun() method is called, we expect User.findById() to be called once and Order.findByUserAndId() to be called once as well. Spock then allows us to stub out each method call so that we specify what we want the method to return. When we run the test, the stub will be used, not the actual GORM method.
Some complexity lies with stubbing out static methods (like GORM methods), but you can use a GroovySpy to get the job done.
Also, I'm assuming you meant to use User.findById() instead of User.findByUserId()?
Something along these lines should work for you:
def "test funtest"() {
setup:
// Global so that it replaces all instances/references of the
// mocked type for the duration of the feature method.
GroovySpy(User, global: true)
GroovySpy(Order, global: true)
when:
def result = service.testfun(2,3)
then:
// No need to return real objects, so use a mock
1 * User.findById(2) >> Mock(User)
1 * Order.findByUserAndId(_ as User, 3) >> Mock(Order)
result == true
when:
result = service.testfun(2,3)
then:
1 * User.findById(2) >> null
result == false
}
Note that we've isolated the service method. Any collaborating objects (User and Order) are only being interacted with via stubs and we can test the functionality of the service method without worrying about GORM at all.

Grails : Spock : Unit testing GORM domain class hooks

Usually I was ending up writing test cases for a Domain by writing them for constraints and any custom methods(created by us in application) as we know we shouldn't test obvious.
But the time we started using coverage plugin, we found that our domains line of code is not fully covered which was due to gorm hooks(onInsert, beforeUpdate) that we never wrote test cases for.
Is there a way we can test these. One possible way that seems obvious but not suitable is to call another method(containing all code which was earlier in hooks) within these hooks and test that method only and be carefree for hooks.
Any solutions...
Edit
Sample code in domain that I want to unit-test:
class TestDomain{
String activationDate
def beforeInsert() {
this.activationDate = (this.activationDate) ?: new Date()//first login date would come here though
encodePassword()
}
}
How can I unit-test beforeInsert or I would end up writing integration test case?
Perhaps a unit test like:
import grails.test.mixin.TestFor
#TestFor(TestDomain)
class TestDomainSpec extends Specification {
def "test beforeSave"() {
given:
mockForConstraintsTests(TestDomain)
when:
def testDomain = new TestDomain().save(flush:true)
then:
testDomain.activationDate != null
}
}

How do I mock local variables of a mocked class in a Spock test?

Let's say I have the following method in a service:
private void deleteItems(List<Item> itemsToDelete) {
def sql = new Sql(dataSource)
itemsToDelete?.each { Item item ->
sql.execute("DELETE FROM owner_item WHERE item_id = ${item.id}")
item.delete(flush: true, failOnError: true)
flushDatabaseSession();
}
}
How do I create a test for this method in the ItemServiceSpec? When I try it, I get either a DataSource "Must specify a non-null Connection" error or a nullPointerException on sql.
This is my existing test.
#TestFor(ItemService)
#Mock([Item])
#Build([Item])
class SubjectServiceSpec extends Specification {
...
def "delete items"() {
given:
Item item1 = Item.build().save(flush: true)
Item item2 = Item.build().save(flush: true)
Item.count() == 2
DataSource mockDataSource = Mock()
service.dataSource = mockDataSource
1 * deleteItems
when:
service.deleteItems([item1, item2])
then:
Item.count() == 0
}
}
What you are trying to do here, is to mock a dependency (DataSource) of a dependency (Sql). This normally leads to a situation, where you a not 100% aware of how the Sql interacts with the DataSource Object. If Sql changes private interaction with the Datasource in a Version Update, you have to deal with the situation.
Instead of mocking a dependency of a dependency you should the Sql Class directly. For this, the sql has to be some kind of explicit dependency that you can receive via DI or a method parameter. In this case you can just mock the execute call like so (choosen the way of a Expando-Mock, but you could also use Map or the Mock Stuff from Spock):
given:
def sqlMock = new Expando()
sqlMock.execute = { return 'what ever you want or nothing, because you mock a delete operation' }
service.sql = sqlMock
when:
service.deleteItems([item1, item2])
then:
assertItemsAreDeletedAndTheOwnerAsWell()
Thinking about the whole testcase, there a two major problems in my opinion.
The first one is, when you ask yourself what kind of certainty do you really get here by mocking out the whole sql stuff. In this case, the only thing that you are doing here is to interact with the db. When you mock this thing out, then there is nothing anymore that you could test. There is not many conditional stuff or anything that should be backed up by a unit test. Due to this, I would suggest to write only integration spec for this test-case where you have something like a H2DB for testing purposes inplace.
The second thing is, that you actually don't need the Sql Manipulation at all. You can configure GORM and Hibernate in a way do a automatic and transparent deletion of the owner of the item, if the item is deleted. For this, look at the docs (especially the cascade part) from GORM or directly in the Hibernate docs.
To sum it up: use cascade: 'delete' together with a proper integration test and you have a high amount of certainty and less boilerplate code.

Grails testing user role custom validation constraints using Spring Security Core Plugin

I'm sure this is a fairly common situation. I'm using the Spring Security Core plugin and want to create a domain model that has a Person limited to certain roles:
class Workgroup {
Person manager
...
static constraints = {
manager(validator: {mgr ->
// it feels like there should be a more elegant, groovy way of doing this.
def auths = mgr.getAuthorities();
def returny = false
auths.each {
if(it.authority == 'ROLE_MANAGER')
{
returny = true
}
}
return returny
})
}
}
This test fails like a mofo:
void testInvalidManager() {
def nick = new Person(username:'Nick')
def nonManagerRole = new Role(authority:'ROLE_EMPLOYEE')
UserRole.create(nick,nonManagerRole)
def awesome = new Workgroup(name:'mooCows', manager:nick)
mockForConstraintsTests(Workgroup, [awesome])
assertFalse awesome.validate()
assertEquals "validator", awesome.errors["manager"]
}
testInvalidManager Error No signature of method: users.UserRole.save() is applicable for argument types: (java.util.LinkedHashMap) values: [[flush:false, insert:true]] Possible solutions: wait(), any(), wait(long), use([Ljava.lang.Object;), isCase(java.lang.Object), each(groovy.lang.Closure)
groovy.lang.MissingMethodException: No signature of method: users.UserRole.save() is applicable for argument types: (java.util.LinkedHashMap) values: [[flush:false, insert:true]]
Possible solutions: wait(), any(), wait(long), use([Ljava.lang.Object;), isCase(java.lang.Object), each(groovy.lang.Closure)
at users.UserRole.create(UserRole.groovy:32)
at users.UserRole.create(UserRole.groovy)
at users.UserRole$create.call(Unknown Source)
at users.WorkgroupTests.testInvalidManager(WorkgroupTests.groovy:17)
Is this better covered in Integration than Unit Testing? Do I need to mock UserRole (if so, how?)? How are these types of tests normally done?
UserRole.create() calls save(), so you need to use mockDomain() instead of just mockForConstraintsTests().
But that's only if you're ok with testing the domain model with mocks, which I would never do. The mocking support in Grails should be used when testing Controllers or other classes that use domain classes but shouldn't be bothered with real persistence, creating a database (even in-memory), etc. By removing that dependency you're concentrating on the current tier, trusting that the other tier is already properly tested. But when you use mocking to test domain classes, you're really just testing the mocking framework. So I always use integration tests for domain classes so they run against a real database.
To answer the implicit question from your code example, I'd write the constraint as
static constraints = {
manager validator: { mgr ->
mgr.authorities.find { it.authority == 'ROLE_MANAGER' } != null
}
}
The issue with its bulk is that you're using each() when a regular for loop would be preferable since you can return from a for loop. Use each() only when you really want to invoke the closure on every instance. Here's one that's less groovy than the other one but uses a for loop:
static constraints = {
manager validator: { mgr ->
for (auth in mgr.getAuthorities()) {
if (it.authority == 'ROLE_MANAGER') {
return true
}
}
return false
}
}