使用h2的Grails集成测试NPE

时间:2014-04-14 10:12:11

标签: grails groovy h2 spock

我正在尝试使用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
}

1 个答案:

答案 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
}