【问题标题】:Mocking a Java Interface in JRuby with RSpec-mock使用 RSpec-mock 在 JRuby 中模拟 Java 接口
【发布时间】:2014-11-24 04:23:02
【问题描述】:

我正在为 JRuby 中的 JDBC 编写一个简单的包装器。本质上,我想要一个包装类DBW,它接受一个连接字符串和一个可选的初始化块。

require 'java'

class DBW
    def initialize (connection_string, &optional_init_block)
        if optional_init_block
            yield
        end

        @connection_string = connection_string
    end
    def get_connection
        Java::java.sql.DriverManager.getConnection(@connection_string)
    end
end

但是在我的测试中,我想使用一个测试替身作为Driver 注册到DriverManager,所以我在 RSpec 测试中做了以下操作:

it "can produce a connection using the connection string" do 

    mock_conn = instance_double("Connection") # A dummy connection instance
    mock_driver = instance_double("Driver")
    allow(mock_driver).to receive(:acceptsURL).with(any_args) {
        # this doesn't get called when the wrapper calls getConnection on the DriverManager 
        true
    }
    # Expecting that connect would be called on the driver with the connecion string...
    allow(mock_driver).to receive(:connect).with(any_args).and_return(mock_conn)

    wrapper = DBW.new "jdbc:subprotocol:subname" do 
        # Initialize the DriverManager with the mock driver
        Java::java.sql.DriverManager.registerDriver(mock_driver)
    end

    # This should call in to DriverManager.getConnection
    conn = wrapper.get_connection
    expect(conn).to eq(mock_conn)

end

运行测试时出现以下错误:

Failures:

  1) DBW can produce a connection using the connection string
     Failure/Error: Unable to find matching line from backtrace
     Java::JavaSql::SQLException:
       No suitable driver found for jdbc:subprotocol:subname
     # java.sql.DriverManager.getConnection(java/sql/DriverManager.java:689)
     # java.sql.DriverManager.getConnection(java/sql/DriverManager.java:270)
     # java.lang.reflect.Method.invoke(java/lang/reflect/Method.java:497)
     # RUBY.get_connection(/playground/dbw.rb:12)
     # RUBY.(root)(/playground/specs/dbw_spec.rb:39)

如测试代码中所述,acceptURL 方法没有被DriverManager 调用。有什么我想念的想法吗?

【问题讨论】:

    标签: rspec interface mocking jruby rspec-mocks


    【解决方案1】:

    您很可能会遇到似乎惹恼您的java.sql.DriverManager 内部结构。如果您查看 .java 源代码,您会看到在调用者的加载程序上获取连接时会进行检查(在调用 connect 之前 - acceptsURL 与此处无关)。这可能是在 JRuby 中爆炸的东西,您可以验证 java.sql.Driver 生成的实例是否存在,但在使用 API 时未返回:

    java.sql.DriverManager.class_eval do
      field_reader :registeredDrivers
    end
    
    # ...
    
    Java::java.sql.DriverManager.registerDriver(mock_driver)
    
    puts java.sql.DriverManager.registeredDrivers.to_s # returns the mock_driver (last)
    # [driver[className=sun.jdbc.odbc.JdbcOdbcDriver@55974e79], driver[className=org.jruby.gen.InterfaceImpl1708146542@b02cbee]]
    puts java.sql.DriverManager.getDrivers.to_a.inspect  # does not return the mock_driver
    # [#<Java::SunJdbcOdbc::JdbcOdbcDriver:0x55974e79>]
    

    我建议你重构你的代码不要太紧DriverManager...或者干脆尝试用一个“真实的”(Java)模拟驱动程序编译成一个添加到类路径的.jar

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-14
      相关资源
      最近更新 更多