在 jUnit 测试的 UPDATE 语句中使用 jOOQs MockResult class
Using jOOQs MockResult class in an UPDATE statement for jUnit tests
我正在努力为我的 DAO 层设置一些单元测试用例,以确保它以我需要的方式响应,为此我需要对我的 jOOQ 代码进行单元测试。我现在是 运行 jOOQ 3.6.1,并尝试使用 jOOQ documentation.
中 link 中描述的 JDBC 模拟
我的单元测试环境正在利用 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 对象?也许我误解了,但我相信更新 returns 我的记录数受到影响,基于我返回的 MockResult 应该是 1。但是 UserDAO 对象返回的是 0,因此我的测试失败了。
在此先感谢您的帮助,或我可以解决此问题的方向。
我不知道我这样做对不对,因为我是在回答我自己的问题,但我想我是对的。在过去的两天里,我一直在研究这个问题并单步执行 jOOQ 代码以查看问题所在。事实证明,问题出在我在这行测试中的 MockResult 对象中提供的数据中:
result[0] = new MockResult(1, userRecordResult);
因为更新后我没有获取数据,所以我不应该包含它。基本上,我可以删除构建 userRecordResult 对象的所有代码行,而只需按如下方式设置 MockResult 对象:
result[0] = new MockResult(1, null);
我相信这对我来说是有结果,但没有数据。由于现在没有数据返回,MockStatement.execute0() function now returns false instead of true. And then when in the AbtractQuery.execute() 函数,第 410 - 413 行的 if 块被触发,结果计数被设置为该值。
if (!stmt.execute()) {
result = stmt.getUpdateCount();
ctx.rows(result);
}
之前,当我在 MockResult 对象中获取数据时,MockStatement.execute0() 函数返回 true,因此上面的 if 块从未执行,并且 result
int 从未更改从创建时开始为零。但是对于空数据,行 result = stmt.getUpdateCount();
被触发并设置了我的值。
我正在努力为我的 DAO 层设置一些单元测试用例,以确保它以我需要的方式响应,为此我需要对我的 jOOQ 代码进行单元测试。我现在是 运行 jOOQ 3.6.1,并尝试使用 jOOQ documentation.
中 link 中描述的 JDBC 模拟我的单元测试环境正在利用 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 对象?也许我误解了,但我相信更新 returns 我的记录数受到影响,基于我返回的 MockResult 应该是 1。但是 UserDAO 对象返回的是 0,因此我的测试失败了。
在此先感谢您的帮助,或我可以解决此问题的方向。
我不知道我这样做对不对,因为我是在回答我自己的问题,但我想我是对的。在过去的两天里,我一直在研究这个问题并单步执行 jOOQ 代码以查看问题所在。事实证明,问题出在我在这行测试中的 MockResult 对象中提供的数据中:
result[0] = new MockResult(1, userRecordResult);
因为更新后我没有获取数据,所以我不应该包含它。基本上,我可以删除构建 userRecordResult 对象的所有代码行,而只需按如下方式设置 MockResult 对象:
result[0] = new MockResult(1, null);
我相信这对我来说是有结果,但没有数据。由于现在没有数据返回,MockStatement.execute0() function now returns false instead of true. And then when in the AbtractQuery.execute() 函数,第 410 - 413 行的 if 块被触发,结果计数被设置为该值。
if (!stmt.execute()) {
result = stmt.getUpdateCount();
ctx.rows(result);
}
之前,当我在 MockResult 对象中获取数据时,MockStatement.execute0() 函数返回 true,因此上面的 if 块从未执行,并且 result
int 从未更改从创建时开始为零。但是对于空数据,行 result = stmt.getUpdateCount();
被触发并设置了我的值。