Archive

Posts Tagged ‘Neo4j;Grails;Unit Testing’

On Grails Neo4j and unit integration testing …

March 22, 2014 Leave a comment

Life is never as easy as you imagine …

So first get your grails environment set up, i’m using GGTS 3.5M2 and grails 2.3.7

Create yourself a grails project and wait for all the scripts to finish. Then in your projects /conf/BuildConfig you need to the add the following plugin -> :neo4j:1.1.1, and whilst your at it you need to comment out the database-migration plugin as there is a bug somewhere that stops your integration tests from running. ( i have left the hibernate plugin installed as i am setting the static mapWith clause on the domain classes i want to persist through Neo4j (trying mixed mode persistence and see what happens))

   plugins {
	compile ":neo4j:1.1.1"
		
        // plugins for the build system only
        build ":tomcat:7.0.52.1"

        // plugins for the compile step
        compile ":scaffolding:2.0.2"
        compile ':cache:1.1.1'

        // plugins needed at runtime but not for compilation
        runtime ":hibernate:3.6.10.9" // or ":hibernate4:4.3.4"
        //runtime ":database-migration:1.3.8"
        runtime ":jquery:1.11.0.2"
        runtime ":resources:1.2.7"
        // Uncomment these (or add new ones) to enable additional resources capabilities
        //runtime ":zipped-resources:1.0.1"
        //runtime ":cached-resources:1.1"
        //runtime ":yui-minify-resources:0.1.5"

        // An alternative to the default resources plugin is the asset-pipeline plugin
        //compile ":asset-pipeline:1.6.1"

        // Uncomment these to enable additional asset-pipeline capabilities
        //compile ":sass-asset-pipeline:1.5.5"
        //compile ":less-asset-pipeline:1.5.3"
        //compile ":coffee-asset-pipeline:1.5.0"
        //compile ":handlebars-asset-pipeline:1.3.0.1"
    }

also we’ll start with embeddedGraphDatabase mode – but you still need to inform grails where the backing store is in /conf/DataSource.groovy – else it’ll moan saying it can’t find grails.neo4j configuration if you don’t do this. The directory you point the database in must be writable on your local machine. I added mine just above the environments section in DataSource.groovy like this

grails {
	neo4j {
			type = "embedded"
			location = "users/802518659/Documents/data/neo4j"
			params = []
	}
}
...

The plugins user guide can be found here

With that in place – your ready to go. You start as normal and write a domain class – say something like this. Note the mapWith clause to tell grails to use Neo

domain:com.softwood.interaction.groovy

class Interaction {

String name
//List tasks //declared i wanted a list not a set

static hasMany = [tasks: Task]

static mapWith = “neo4j”

static constraints = {
name nullable:true
}
}
[/sourcode]

Now some quick notes on testing. When you create a domain class GGTS will automatically create a spoc unit test for you (new default in GGTS).

So now some more fun. Spoc is great, and i’ll post something separately about spoc and grails.

For now you need to know a couple of things (and i forgot of course). Grails does lots of Dynamic additions to your domain classes – so what looks simple as you type generates a complex class with loads of extra ‘Grails’ goodness including addTo() methods if you have a one to many defined on the one side.

However, in unit testing mode this embellishment does not take place and you pretty much get your plain POJO. This can be confusing as you imagine that this embellishment always happens. It does in integration and real running (the grails framework is brought up for both ) but not in unit testing

so if you write a test like this for the domain class like this

unit test:InteractionSpec

@TestFor(Request)
@Mock (Task) // add this to Mock the collaborator class
class RequestSpec extends Specification {
..
void “test create”() {
given:

Interaction req = new Interaction (name:”job1”)

when:
assertTrue req.validate()
req.save (flush:true) //

def task1 = new Task (name: ‘new task’)
assert task1
assert task1.validate()

req.addToTasks (task1) //fails unit test – cant find addToTasks method

[/sourceocde]

Most disconcerting, So whats going on. Its a unit test so that extra goodness hasn’t been added. This is what i’d forgotten. If you look in the manual it shows you about unit testing a controller say and using the @Mock ([…]) for the domain collaborators. But here your trying to unit test the domain class itself.

Once you get that then there are two ways round it. One the brute force path, is to do the work manually like this

...
		req.tasks = new HashSet()
		task1.job = req
		req.tasks.add (task1)
		req.save(flush:true ) //often have to flush this in unit test else grails wont write immediately

However this is alot of extra work. The other approach is to use the @Mock ([…]) after the @TestFor () like this, and add the domain class and any collaborator classes to the array of classes to Mock. You’ll now note that the respondsTo method assertion now passes, and the whole test will pass.

@TestFor(Interaction)
@Mock ([Interaction, Task])
class InteractionSpec extends Specification {

    def setup() {
    }

    def cleanup() {
    }

    void "test create"() {
				
		given: 
		def interaction = new Interaction (name: "first job")
		def task1 = new Task (name:"task1")
		def task2 = new Task (name:"task2")
		
		when:
		assert interaction.respondsTo ("addToTasks")
		def res =   interaction.save (flush: true)
		Interaction thing = Interaction.get (1)
		thing.addToTasks (task1)
		thing.addToTasks (task2)
		
		def tasks = thing.tasks.collect{it.name}.sort()
		
		then:
		assert thing.name == "first job"
		assert thing.tasks.size() == 2
		assert ["task1", "task2"] == tasks
		
    }
}

%d bloggers like this: