可用版本:Dev (3.21) | 最新 (3.20) | 3.19 | 3.18 | 3.17 | 3.16 | 3.15 | 3.14 | 3.13 | 3.12 | 3.11

模拟连接

适用于 ✅ 开源版   ✅ 专业版   ✅ 企业版

在为您的数据访问层编写单元测试时,您可能已经使用了一些流行的提供程序(如 Mockitojmockmockrunner 甚至 DBUnit)提供的通用模拟工具。使用 jOOQ,您可以利用内置的 JDBC 模拟 API,该 API 允许您在 JDBC 级别模拟一个简单的数据库,专门用于 jOOQ 支持的 SQL/JDBC 用例。

免责声明:使用此 jOOQ API 模拟 JDBC 连接的一般想法是使用非常简单的 JDBC 抽象来提供快速的解决方案、注入点等。不建议 使用此模拟 API 来模拟整个数据库(包括复杂的状态转换、事务、锁定等)。一旦您有此需求,请考虑使用实际的数据库产品进行集成测试,而不是在 MockDataProvider 中实现您的测试数据库。

模拟 JDBC API

JDBC 是一个非常复杂的 API。编写一个有用且正确的模拟实现需要花费大量时间,至少需要实现以下接口:

或者,您甚至可能想要实现接口,例如 java.sql.Arrayjava.sql.Blobjava.sql.Clob 以及许多其他接口。除此之外,您可能还需要找到一种方法来同时支持不兼容的 JDBC 次要版本,例如 4.0、4.1。

使用 jOOQ 自己的模拟 API

当使用 jOOQ 自己的模拟 API 时,这项工作会大大简化。org.jooq.tools.jdbc 包包含 JDBC 4.0 和 4.1 的所有基本实现,这些实现是模拟 jOOQ 的 JDBC 所需的。为了编写模拟测试,请为 jOOQ Configuration 提供一个 MockConnection,并实现 MockDataProvider

// Initialise your data provider (implementation further down):
MockDataProvider provider = new MyProvider();
MockConnection connection = new MockConnection(provider);

// Pass the mock connection to a jOOQ DSLContext:
DSLContext create = DSL.using(connection, SQLDialect.ORACLE);

// Execute queries transparently, with the above DSLContext:
Result<BookRecord> result = create.selectFrom(BOOK).where(BOOK.ID.eq(5)).fetch();

正如您所看到的,配置设置很简单。现在,MockDataProvider 充当您与 JDBC / jOOQ 的单一联系点。它透明地统一了这些执行模式:

  • 没有结果的语句
  • 没有结果但具有生成键的语句
  • 具有结果的语句
  • 具有多个结果的语句
  • 具有单查询和多绑定值集的批量语句
  • 具有多查询且没有绑定值的批量语句

以上是 jOOQ 支持的执行模式。无论您使用 jOOQ 的哪种获取模式(例如 pojo 获取延迟获取多重获取稍后获取)都无关紧要,因为这些模式都建立在标准 JDBC API 之上。

实现 MockDataProvider

现在,这是如何实现 MockDataProvider 的方法:

public class MyProvider implements MockDataProvider {

    @Override
    public MockResult[] execute(MockExecuteContext ctx) throws SQLException {

        // You might need a DSLContext to create org.jooq.Result and org.jooq.Record objects
        DSLContext create = DSL.using(SQLDialect.ORACLE);
        MockResult[] mock = new MockResult[1];

        // The execute context contains SQL string(s), bind values, and other meta-data
        String sql = ctx.sql();

        // Exceptions are propagated through the JDBC and jOOQ APIs
        if (sql.toUpperCase().startsWith("DROP")) {
            throw new SQLException("Statement not supported: " + sql);
        }

        // You decide, whether any given statement returns results, and how many
        else if (sql.toUpperCase().startsWith("SELECT")) {

            // Always return one record
            Result<Record2<Integer, String>> result = create.newResult(AUTHOR.ID, AUTHOR.LAST_NAME);
            result.add(create
                .newRecord(AUTHOR.ID, AUTHOR.LAST_NAME)
                .values(1, "Orwell"));
            mock[0] = new MockResult(1, result);
        }

        // You can detect batch statements easily
        else if (ctx.batch()) {
            // [...]
        }

        return mock;
    }
}

本质上,MockExecuteContext 包含所有必要的信息,供您决定应返回哪种数据。MockResult 封装了两个信息:

您应该返回与查询执行次数(在 批量模式 下)或结果数(在 多重获取模式 下)一样多的 MockResult 对象。但是,您可以构造一个“更友好”的 org.jooq.Result,其中包含您自己的记录类型,而不是笨拙的 java.sql.ResultSet。jOOQ 模拟 API 将使用此 Result 提供的元数据来创建必要的 JDBC java.sql.ResultSetMetaData

有关您应遵循的规则列表,请参阅 MockDataProvider Javadoc

反馈

您对此页面有任何反馈吗?我们很乐意听取您的意见!

The jOOQ Logo