java - 在 jUnit 测试的 UPDATE 语句中使用 jOOQs MockResult 类

标签 java sql jooq

我正在努力为我的 DAO 层设置一些单元测试用例,以确保它以我需要的方式响应,为此,我需要对我的 jOOQ 代码进行单元测试。我此时正在运行 jOOQ 3.6.1,并尝试使用 JDBC 模拟,如 jOOQ documentation 中的此链接中所述。 .

我的单元测试环境正在利用 jUnit 4.12 和mockito。

不幸的是,虽然这对于 SELECT 查询非常有效,但我很难弄清楚我在 UPDATE 查询中做错了什么。在非 jUnit 单元测试中,我知道该函数本身正在工作(它也非常基本,因此并不令人震惊),但我也希望能够对这段代码进行一些自动化单元测试。

我的单元测试按以下方式设置:

public class UserDAOTest {
    private static UserDAO userDAO;
    private static Logger LOG = Logger.getLogger(UserDAOTest.class.getName());

    private class MyMockDataProvider implements MockDataProvider {

    @Override
    public MockResult[] execute ( MockExecuteContext ctx ) throws SQLException {
        DSLContext create = DSL.using(SQLDialect.MYSQL);
        MockResult[] result = new MockResult[1];

        String sql = ctx.sql();

        if ( sql.toUpperCase().startsWith("UPDATE") ) {
            Result<UserRecord> userRecordResult = create.newResult(USER);
            userRecordResult.add(create.newRecord(USER));
            userRecordResult.get(0).setValue(USER.ID, 1000);
            userRecordResult.get(0).setValue(USER.USERNAME, "BrumbyUpdateTest");
            userRecordResult.get(0).setValue(USER.CREATED_ON, new Timestamp((new Date()).getTime()));
            userRecordResult.get(0).setValue(USER.UPDATED_ON, new Timestamp((new Date()).getTime()));
            userRecordResult.get(0).setValue(USER.USER_TYPE, "Poster");
            userRecordResult.get(0).setValue(USER.PASSWORD, BCrypt.hashpw("12341234", BCrypt.gensalt()));
            result[0] = new MockResult(1, userRecordResult);
        }
        LOG.info("[execute] :: MockResult.rows=" + result[0].rows);
        LOG.info("[execute] :: MockResult.data=" + result[0].data);
        LOG.info("[execute] :: result=" + result.toString());
        return result;
    }

    @Before
    public void setupTest() {
        DataSourceFactory mockDataSource = mock(DataSourceFactory.class);
        ManagedDataSource ds = mock(ManagedDataSource.class);
        when(mockDataSource.build(any(), any())).thenReturn(ds);
        Environment environment = mock(Environment.class);
        try {
            when(ds.getConnection()).thenReturn(connection);
        } catch (SQLException sqle) {
            LOG.warning("[setupTest] :: sqle=" + sqle.getMessage());
        }
        userDAO = new UserDAO(mockDataSource.build(environment.metrics(), "ds"));
    }

    @Test
    public void testUpdatePassword() {
        boolean out = userDAO.updatePassword(1000, "12341234");
        assertThat(out).isEqualTo(true);
    }
}

我阅读jOOQ JavaDocs的理解是这应该最终使用 MyMockDataProvider 并在使用我创建的结果执行 UPDATE 查询时做出响应。我相信我正在创建一个新的 MockResult,其行数为 1,并且其中指定了 User 对象。当我查看放入其中的日志语句时,这就是正在发生的事情。

    Jul 23, 2015 9:23:04 AM com.mycompany.dao.UserDAOTest$MyMockDataProvider execute
    INFO: [execute] :: MockResult.rows=1
    Jul 23, 2015 9:23:04 AM com.mycompany.dao.UserDAOTest$MyMockDataProvider execute
    INFO: [execute] :: MockResult.data={Expected Data Based on MyMockProvider}

但是当我执行单元测试时,UserDAO 对象将来自 jOOQ 的响应视为记录计数 0。

    Jul 23, 2015 9:23:04 AM com.mycompany.dao.UserDAO updatePassword
    WARNING: [updatePassword] :: count=0

我尝试测试的代码如下:

public class UserDAO {
    public boolean updatePassword ( Integer id, String newPassword ) {
        try ( Connection conn = ds.getConnection() ) {
            DSLContext updatePassword = DSL.using(conn, SQLDialect.MYSQL);
            int count = updatePassword.update(USER)
                    .set(USER.PASSWORD, BCrypt.hashpw(newPassword, BCrypt.gensalt()))
                    .where(USER.ID.eq(id))
                    .execute();
            LOG.warning("[updatePassword] :: count=" + count);
            if ( count != 1 ) return false;
            return true;
        } catch ( SQLException sqle ) {
            LOG.warning("[updatePassword] :: sqle=" + sqle.getMessage());
            return false;
        }
    }
}

我是否错误地使用了 MockResult 对象?也许我有误解,但我相信更新会返回受影响的记录数,根据我返回的 MockResult,该记录数应该为 1。但是 UserDAO 对象返回 0,因此我的测试失败了。

预先感谢您的任何帮助,或者我可以解决此问题的方向。

最佳答案

我不知道我这样做是否正确,因为我正在回答自己的问题,但我认为我是。我花了两天的时间研究这个问题并单步执行 jOOQ 代码以了解问题所在。事实证明,问题在于我在测试的这一行中的 MockResult 对象中提供的数据:

result[0] = new MockResult(1, userRecordResult);

由于我在更新后没有获取数据,所以我不应该包含它。基本上,我可以删除构建 userRecordResult 对象的所有代码行,而只需设置 MockResult 对象,如下所示:

result[0] = new MockResult(1, null);

我相信这对我来说有一个结果,但没有数据。由于现在没有返回数据,MockStatement.execute0()函数现在返回 false 而不是 true。然后当在AbtractQuery.execute()时函数中,第 410 - 413 行的 if block 被触发,结果计数被设置为该值。

        if (!stmt.execute()) {
            result = stmt.getUpdateCount();
            ctx.rows(result);
        }

之前,当我在 MockResult 对象中拥有数据时,MockStatement.execute0() 函数返回 true,因此上面的 if block 从未执行,并且 result int 从创建时起从未更改为零。但对于空数据,会触发 result = stmt.getUpdateCount(); 行并设置我的值。

关于java - 在 jUnit 测试的 UPDATE 语句中使用 jOOQs MockResult 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31591608/

相关文章:

java - 如何解析获取请求响应以获取所有键和值对?

java - 查找数组中差为 k 的对数的最佳方法

java - Javascript JNI 覆盖类型中 Long 的 GWT 问题

php - 对这些术语查询使用 ORDER BY

java - 具有 MockResult 抛出 DataTypeException 的 Jooq 自定义类型

java - JOOQ 将类型强制转换为 boolean 值

java - 如何禁用除特定输入之外的键盘输入,或在使用错误的输入时显示错误?

sql - 从两个表中选择一列并将它们放入一个

python - 如何在 SQL 中找到时间戳中的间隙(对于数据抓取器)

java - 将条件列表传递给 JOOQ 中的 WHERE 子句