angryip February 2016

How to mock an SQL call in Groovy/Grails Spoc

I have a service class written in groovy, as follows:

import groovy.sql.Sql
import javax.sql.DataSource
import java.sql.SQLException

class DatabaseService {

    DataSource dataSource;

    void registerUser(User user) {
        try {
            def sql = new Sql(dataSource);
            sql.call("{call regUser(?)}", [user.name])
        } catch (SQLException e) {
            log.error("unable to register the user", e)
            throw e;
        }
    }
}

What I want to do here, is Mock the sql.call method, to throw an SQLException. Writing an integration test to do this, at this time, is not possible.

Here is what I have so far:

void "test registerDeveloper exception handling"() {
    String expectedErrorMsg = "exception from test"
    DataSource mockedSource = Mock(DataSource)
    User user = new User(name: "joe")
    Sql mockedSql = Mock(Sql)
    DatabaseService databaseService = new DatabaseService(dataSource:mockedSource)

    given:
    mockedSql.call(_,_) << {throw new SQLException()}

    when:
    databaseService.registerUser(user)

    then:
    def exception = thrown(SQLException)
    exception.message == expectedErrorMsg
} 

With the above code, I get this error:

groovy.lang.MissingMethodException: No signature of method: java.lang.Integer.leftShift() is applicable for argument types: (UcopRip.DatabaseServiceSpec$__spock_feature_0_0_closure1) values: [UcopRip.DatabaseServiceSpec$__spock_feature_0_0_closure1@77049094] Possible solutions: leftShift(java.lang.Number), rightShift(java.lang.Number)

If I change << to >>, I get this error: Expected exception of type 'java.sql.SQLException', but got 'java.lang.NullPointerException', poiting to sql.call line in the DatabaseService class.

Does anyone have an idea what I am doing wrong? I am certainly new to testing with SPOCK, but cannot seem to find anywhere online where people are mocking SQL me

Answers


Jérémie B February 2016

Interaction should be in a when clause, and use >> Moreover 'Sql' is a class, and is created in your service : you can't mock it really easily. it's more simple to test this kind of things with an in-memory db like hsqldb, but you can mock the connection and preparedstatement (it's ugly)

void "test registerDeveloper exception handling"() {
    given:
      String expectedErrorMsg = "exception from test"

      DataSource mockedSource = Mock(DataSource)

      def user = new User(name: "joe")
      def databaseService = new DatabaseService(dataSource:mockedSource)

    when:
      databaseService.registerUser(user)

    then:
       1* mockedSource.getConnection() >> {throw new SQLException(expectedErrorMsg)}

    and:
      def exception = thrown(SQLException)
      exception.message == expectedErrorMsg
} 

Post Status

Asked in February 2016
Viewed 1,130 times
Voted 8
Answered 1 times

Search




Leave an answer