Grails integration testing NPE using h2
Question
I am trying to write an integration test in grails using an h2 database. I'm using h2 so I don't have to setup a database in the CI server. However I'm having problems initializing the data in my database.
This is what my test looks like right now:
class PathGeneratorServiceSpec extends Specification {
def pathGeneratorService
def setup() {
PathSeed pathSeed = new PathSeed(id:1, seed:0).save()
}
void "getNextPath should return a string"() {
when:
def retVal = pathGeneratorService.getNextPath()
then:
retVal instanceof String
}
}
However when I try to run my test I'm getting a NPE: Cannot get property 'seed' on null object
This is what my service looks like by the way:
public String getNextPath() {
def seedValue = getNextSeed()
def path = createPath(seedValue)
return path
}
private def getNextSeed() {
def seedValue
PathSeed.withTransaction { txn ->
def seed = PathSeed.lock(1)
seedValue = seed.seed
seed.seed++
seed.save()
}
return seedValue
}
Solution
I think the problem is caused by your attempt to assign a value to the identity column. If you replace this:
PathSeed pathSeed = new PathSeed(id:1, seed:0).save()
with
PathSeed pathSeed = new PathSeed(seed:0).save()
and also replace:
PathSeed.lock(1)
with:
PathSeed.first()
Does that solve your problem? You should never need to explicitly assign a value to id
, and you should avoid hardcoding ID values, e.g. PathSeed.lock(1)
Update
You asked in a comment
is there any way to lock the database using first?
No, but you can adapt the solution above to use pessimistic locking like so:
class PathGeneratorServiceSpec extends Specification {
def pathGeneratorService
private Long pathSeedId
def setup() {
pathSeedId = new PathSeed(seed:0).save().id
}
void "getNextPath should return a string"() {
when:
def retVal = pathGeneratorService.getNextPath(pathSeedId)
then:
retVal instanceof String
}
}
public String getNextPath(id) {
def seedValue = getNextSeed(id)
def path = createPath(seedValue)
return path
}
private def getNextSeed(id) {
def seedValue
PathSeed.withTransaction { txn ->
def seed = PathSeed.lock(id)
seedValue = seed.seed
seed.seed++
seed.save()
}
return seedValue
}