0

So we have a restful service that we want to test using a restclient in grails.

The test code should go something like this...

class MyControllerSpec extends Specification {

def setup() {
  this.dbEntity = new DbEntity("someid123").save();
}

void "Test entity GET"{
        given:
            RestBuilder rest = new RestBuilder()

        when: "The DB entity service is hit"
            RestResponse restResponse = rest.post("http://localhost:8080/api/someentity/$id");

        then: "A 200 error is sent"
            restResponse.status == 200


}

The problem I am having is the setup method blows up on .save() because there is not hibernate session. How can I manipulate my database before running a test?

benstpierre
  • 32,833
  • 51
  • 177
  • 288

4 Answers4

0

You can define a method named like "setupData", and call it in the "given" block of "Test entity GET" testcase.

def setupData() { this.dbEntity = new DbEntity("someid123").save(); }
Andy.D
  • 11
  • 6
0

If you need to load some data before each funcional test, you can create a helper class, with @Shared variables or methods or both. Even you could override the setup, setupSpec methods in that class.

Your first class does not extends Specification now, DataLoader class (helper class) instead.

class MyControllerSpec extends DataLoader {

    void setup(){
        createEntity()
    }


    void "Test entity GET"{
            given:
                RestBuilder rest = new RestBuilder()

            when: "The DB entity service is hit"
                RestResponse restResponse = rest.post("http://localhost:8080/api/someentity/$dbEntity.id");

            then: "A 200 error is sent"
                restResponse.status == 200

    }
}

And your helper class is the one which extends Specification, with its methods and @Shared variables.

import spock.lang.Shared

class DataLoader extends Specification {

    @Shared DbEntity dbEntity

    void createEntity(){
        dbEntity = new DbEntity("someid123").save();
    }

}
quindimildev
  • 1,280
  • 8
  • 21
0

When extending GebSpec in Grails 2.5.6, none of the other answers helped: I would still get

Method on class [...] was used outside of a Grails application

on the save() call.

Adding @TestFor(DbEntity) to the test class helped.

NB: While that annotation breaks integration tests, it seems to be necessary here. Not sure why that is.

Raphael
  • 9,779
  • 5
  • 63
  • 94
  • This only kind-of works if you have _one_ type you need to do this with, and cleanup isn't really possible. – Raphael Nov 13 '18 at 08:27
0

You probably want to use the remote-control plugin. In Grails 2.x, add this to your BuildConfig.groovy:

repositories {
    ...
    mavenRepo "http://dl.bintray.com/alkemist/maven/"
}

plugins {
    ...
    test ":remote-control:2.0"
}

After refreshing dependencies and potentially adjusting some settings (see e.g. here and here), you can use it like so in tests:

// <project>/test/functional/<package>/MyControllerSpec.groovy
class MyControllerSpec extends GebSpec {

    RemoteControl remote        

    DbEntity dbEntity

    def setup() {
        this.remote = new RemoteControl()           

        this.dbEntity = remote {
            new DbEntity("someid123").save()
        }
    }

    def cleanup() {
        remote {
            DbEntity.findAll().each { dbe ->
                println("Deleting $dbe")
                dbe.delete()
            }
        }
    }

Note:

  • You can invoke remote in given/setup and when blocks as well.
  • Sometimes, it seems to be necessary to wrap core in remote { ... } in a DbEntity.withTransaction { ... }. Maybe that's obvious for the more intitiated; I stumbled over that.
  • If you want to return a DbEntity from remote it must be serializable.
Raphael
  • 9,779
  • 5
  • 63
  • 94