如何在 Groovy/Grails Spoc 中模拟 SQL 调用

How to mock an SQL call in Groovy/Grails Spoc

我有一个服务class写在groovy,如下:

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;
        }
    }
}

我想在这里做的是模拟 sql.call 方法,抛出一个 SQLException。编写集成测试来执行此操作目前是不可能的。

这是我目前的情况:

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
} 

使用上面的代码,我得到这个错误:

groovy.lang.MissingMethodException:没有方法签名:java.lang.Integer.leftShift() 适用于参数类型:(UcopRip.DatabaseServiceSpec$__spock_feature_0_0_closure1) 值:[UcopRip.DatabaseServiceSpec $__spock_feature_0_0_closure1@77049094] 可能的解决方案:leftShift(java.lang.Number), rightShift(java.lang.Number)

如果我将 << 更改为 >>,我会收到此错误: 类型 'java.sql.SQLException' 的预期异常,但得到 'java.lang.NullPointerException',指向数据库服务 class 中的 sql.call 行。

有人知道我做错了什么吗?我当然不熟悉使用 SPOCK 进行测试,但似乎无法在网上找到人们嘲笑 SQL 方法的任何地方。

交互应在 when 子句中,并使用 >> 此外 'Sql' 是一个 class,并且是在您的服务中创建的:您不能很容易地模拟它。使用像 hsqldb 这样的内存数据库来测试这种东西更简单,但是你可以模拟连接和准备语句(它很丑)

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
}