I'm trying to write an integration test for my Grails service class using Spock.
To get some data to drive the test, I have a query like this:
"select column1, column2, column3 from table where column1 = ?"
I get the results from that query using a custom service that we wrote. Basically, it wraps up Groovy's Sql class and handles opening and closing database connections for me. I can inject that into my integration test just fine using Grails' typical dependency injection. However, I can't seem to use it to retrieve data for a data-driven test. Here's my test class:
class MyServiceSpec extends Specification {
def myService
def sqlService
@Shared tsQuery
@Shared ts
def setupSpec() {
tsQuery = "select column1, column2, column3 from table where column1 = ?"
ts = sqlService.rows(tsQuery, ['someSuch'])
}
def "test a feature"() {
setup:
def ts = sqlService.rows(tsQuery)
def results = myService.getTimesheets(thing1, thing2, thing3)
expect:
//some appropriate expectations based on the data here
where:
timeSheet << ts
thing1 = timeSheet.column1
thing2 = timeSheet.column2
thing3 = timeSheet.column3
}
}
That throws an error that I'm not allowed to call sqlService in the setupSpec() block:
Only @Shared and static fields may be accessed from here
ts = sqlService.rows(tsQuery)
^
The problem is, if I make sqlService @Shared
, Grails dependency injection doesn't work and it just creates a null object. Same thing if I try making it static (as in static def sqlService
).
java.lang.NullPointerException: Cannot invoke method rows() on null object
Workarounds I've Tried
A new SqlService Instance in setupSpec
I tried just initalizing a new SqlService instance, like this in my setupSpec block:
def setupSpec() {
tsQuery = "select column1, column2, column3 from table where column1 = 'someSuch'"
def sql = new SqlService()
ts = sql.rows(tsQuery)
}
That just gives an error
| Error 2014-06-13 14:52:10,932 [main] ERROR common.SqlService - Error in sqlQuery: Ambiguous method overloading for method groovy.sql.Sql#. Cannot resolve which method to invoke for [null] due to overlapping prototypes between: [interface javax.sql.DataSource] [interface java.sql.Connection]
Defining sqlService in the setup method
If, instead of using setupSpec() I just use setup(), and put a def sqlService
in it, then the sqlService object is null and thus I get a "Cannot invoke method rows() on null object" error.
If I instead def sqlService = new SqlService()
, then I get the same error as if I did that in setupSpec(), saying that there are overlapping prototypes between javax.sql.Datasource and java.sql.Connection.
Bottom Line
Anyone know how I can use another service class as a data provider in a Spock test?