我正在尝试使用h2数据库在grails中编写集成测试。我使用h2所以我不必在CI服务器中设置数据库。但是,我在初始化数据库中的数据时遇到了问题。
这就是我现在的测试:
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
}
}
然而,当我尝试运行测试时,我得到NPE: Cannot get property 'seed' on null object
顺便说一下,这就是我的服务:
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
}
答案 0 :(得分:0)
我认为问题是由您尝试将值分配给标识列引起的。如果你替换它:
PathSeed pathSeed = new PathSeed(id:1, seed:0).save()
与
PathSeed pathSeed = new PathSeed(seed:0).save()
并替换:
PathSeed.lock(1)
使用:
PathSeed.first()
这可以解决您的问题吗?您永远不需要明确地为id
分配值,您应该避免硬编码ID值,例如PathSeed.lock(1)
您在评论中提问
有没有办法先使用锁定数据库?
不,但您可以调整上面的解决方案,使用悲观锁定,如下所示:
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
}