模拟数据库驱动程序

15

有没有一种JDBC驱动程序可以简单地忽略数据库调用?

为了开发,我正在将一个应用程序迁移到虚拟机上。在这里,我只想处理GUI部分。但是,该应用程序对数据库进行多次请求,这使得应用程序无法启动。此时,我不想更改应用程序代码,因为数据库已经紧密耦合。

所以我在想,可能有一种JDBC驱动程序只返回查询的空结果。


我见过的一种略有不同的方法是使用从文本文件初始化的内存hsqldb来存根数据库。 - flup
7个回答

14

我决定编写一个简单的模拟驱动程序。这非常直接并且做到了我想要的。我可以通过配置文件切换应用程序的数据库驱动程序,因此我可以让应用程序以简单的方式使用我的驱动程序。

然后,我扩展了驱动程序以返回从CSV文件中解析的数据。我在Google Code上发布了代码,也许其他人也可以使用它:dummyjdbc


10

有一些“虚空”JDBC驱动程序是Mocking框架的一部分,例如MockrunnerMockDriver

但是,使用它需要一些编码。

这是因为当Java应用程序连接到数据库时,它提供了一个JDBC URL,格式为jdbc:mysql://localhost。系统正在搜索已注册的驱动程序以处理此类URL,并选择正确的驱动程序。关于驱动程序支持哪种URL类型的信息包含在驱动程序本身中,对于模拟驱动程序来说,它不可能包含所有已知的URL类型-那里没有通配符,并且任何列表都不会完整。

所以,如果您能在应用程序连接到数据库之前调用JDBCMockObjectFactory.registerMockDriver(),它就会完成任务。如果不能-我认为这不可能。但是,对驱动程序代码进行轻微修改就可以做到这一点……但是,再次强调-需要编码。

6

jOOQ带有一个MockConnection,可以提供一个MockDataProvider,这比完整的JDBC API容易实现得多。这篇博客文章展示了如何使用MockConnection:http://blog.jooq.org/2013/02/20/easy-mocking-of-your-database/

一个例子:

MockDataProvider provider = new MockDataProvider() {

    // Your contract is to return execution results, given a context
    // object, which contains SQL statement(s), bind values, and some
    // other context values
    @Override
    public MockResult[] execute(MockExecuteContext context) 
    throws SQLException {

        // Use ordinary jOOQ API to create an org.jooq.Result object.
        // You can also use ordinary jOOQ API to load CSV files or
        // other formats, here!
        DSLContext create = DSL.using(...);
        Result<MyTableRecord> result = create.newResult(MY_TABLE);
        result.add(create.newRecord(MY_TABLE));

        // Now, return 1-many results, depending on whether this is
        // a batch/multi-result context
        return new MockResult[] {
            new MockResult(1, result)
        };
    }
};

// Put your provider into a MockConnection and use that connection
// in your application. In this case, with a jOOQ DSLContext:
Connection connection = new MockConnection(provider);
DSLContext create = DSL.using(connection, dialect);

// Done! just use regular jOOQ API. It will return the values
// that you've specified in your MockDataProvider
assertEquals(1, create.selectOne().fetch().size());

还有MockFileDatabase,它可以通过编写文本文件来将虚拟结果与SQL字符串进行匹配:

# This is a sample test database for MockFileDatabase
# Its syntax is inspired from H2's test script files

# When this query is executed...
select 'A' from dual;
# ... then, return the following result
> A
> -
> A
@ rows: 1

# Just list all possible query / result combinations
select 'A', 'B' from dual;
> A B
> - -
> A B
@ rows: 1

select "TABLE1"."ID1", "TABLE1"."NAME1" from "TABLE1";
> ID1 NAME1
> --- -----
> 1   X
> 2   Y
@ rows: 2

2

我的框架Acolyte是一个经过测试的JDBC驱动程序,专门用于模拟、测试等目的:https://github.com/cchantep/acolyte

它已经被多个开源项目使用,无论是纯Java还是使用其Scala DSL:

// Register prepared handler with expected ID 'my-unique-id'
acolyte.Driver.register("my-unique-id", handler);
// then ...
Connection con = DriverManager.getConnection(jdbcUrl);
// ... Connection |con| is managed through |handler|

@Cities 我知道你的出发点是好的,但是针对一个用户并留下如此多的信息接近骚扰的边缘。请不要再这样做了。请标记并允许管理员处理。 - user3956566
当您编辑帖子以明确包含您的从属关系时,请标记给管理员取消删除。 - user3956566

1

如果您想进行单元测试而非集成测试,那么您可以使用非常基本和简单的方法,仅使用Mockito,例如:

public class JDBCLowLevelTest {

    private TestedClass tested;
    private Connection connection;
    private static Driver driver;

    @BeforeClass
    public static void setUpClass() throws Exception {
        // (Optional) Print DriverManager logs to system out
        DriverManager.setLogWriter(new PrintWriter((System.out)));

        // (Optional) Sometimes you need to get rid of a driver (e.g JDBC-ODBC Bridge)
        Driver configuredDriver = DriverManager.getDriver("jdbc:odbc:url");

        System.out.println("De-registering the configured driver: " + configuredDriver);
        DriverManager.deregisterDriver(configuredDriver);

        // Register the mocked driver
        driver = mock(Driver.class);
        System.out.println("Registering the mock driver: " + driver);
        DriverManager.registerDriver(driver);
    }

    @AfterClass
    public static void tearDown() throws Exception {
        // Let's cleanup the global state
        System.out.println("De-registering the mock driver: " + driver);
        DriverManager.deregisterDriver(driver);
    }

    @Before
    public void setUp() throws Exception {
        // given
        tested = new TestedClass();

        connection = mock(Connection.class);

        given(driver.acceptsURL(anyString())).willReturn(true);
        given(driver.connect(anyString(), Matchers.<Properties>any()))
                .willReturn(connection);

    }
}

然后您可以测试各种情况,就像在任何其他Mockito测试中一样。

@Test
public void shouldHandleDoubleException() throws Exception {
    // given
    SomeData someData = new SomeData();

    given(connection.prepareCall(anyString()))
            .willThrow(new SQLException("Prepare call"));
    willThrow(new SQLException("Close exception")).given(connection).close();

    // when
    SomeResponse response = testClass.someMethod(someData);

    // then
    assertThat(response, is(SOME_ERROR));
}

1

我个人从未听说过这样的驱动程序。如果您找不到它,您可以使用像HSQLDB这样的数据库。您可以将其配置为使用内存表,因此不会写入其他内容到磁盘中。但是,您需要使用不同的连接字符串。


0
如果您正在使用Spring,请创建一个实现Datasource接口的类,并使其方法什么也不做。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接