在测试用例之后使用SQL回滚,但是被测试的方法使用commit



我正试图为我们的应用程序的数据库访问方法之一编写单元测试。我们有一个专用的测试数据库(实时数据库的定期转储/副本)。通常,每个测试用例在单个事务中运行,然后回滚。我们通过在测试用例之前使用Connection.setAutoCommit(false),然后使用Connection.rollback()来实现这一点。

但是这一次,我试图为一个方法写一个测试,它本身做的一切都是一个事务,并在最后使用Connection.commit()

是否有一种方法可以让commit实际上提交到数据库而不会在测试的方法中抛出错误?也就是说,我怎样才能避免这个测试用例真正改变测试数据库的内容?

注意:使用Java, JDBC和Junit。java.sql.Connection用于数据库连接,java.sql.PreparedStatement用于运行查询。

@Before和@After代码:

/**
 * Obtain a new connection and set autoCommit to false.
 * This lets us run a test case then revert all of the changes
 * so the test cases don't interfere with each other.
 */
@Before
public void initConnection() {
    conn = Database.getConnection();
    try {
        conn.setAutoCommit(false);
    } catch (SQLException e) {
        e.printStackTrace();
        fail("Unable to set connection AutoCommit=false");
    }
}
/**
 * Rollback the changes made by the test case
 * and close the connection.
 */
@After
public void rollbackConnection() {
    try {
        conn.rollback();
    } catch (SQLException e) {
        e.printStackTrace();
        fail("Unable to rollback");
    }
    Database.closeConnection(conn);
}

你为什么要这样做?如果您正在编写一个适当的测试,您可能希望验证数据确实已经提交,并且符合您试图完成的任何操作。如果您担心更改,请在完成后清理它们。

但是,如果确实有正当理由,您可以删除事务(txn)代码,编写一个辅助函数,将函数调用封装在事务中,并让客户端调用该辅助函数,测试代码调用原始函数。这可能不是最好的方法,但这是一个选项。

询问同事是否有什么建议。有人建议嘲弄它(使用Mockquito),这让我想到了一个稍微好一点的选择。我正在为Connection创建一个包装器,它扩展了Connection,并像普通连接一样工作,但是当使用其与事务相关的方法时,它的行为不同。

在生产中,使用普通的Connection,对于测试用例,将使用这个包装器类。

专:

  • 当它在每个测试用例的开始被实例化时,它开始一个真正的事务。
  • 当它被告知将autocommit设置为false时(通常我们是如何开始一个长事务的),它创建一个Savepoint并保持它
  • 当它被告知提交时,它释放旧的Savepoint并获得一个新的。
  • 当它被告知回滚时,它回滚到Savepoint
  • 当自动提交设置为false时,将其设置为true释放Savepoint
  • 如果它被告知设置一个Savepoint(如果没有正在进行的事务,它应该启动一个事务),它除了设置请求的Savepoint之外,还像上面一样启动一个假事务。
  • 在测试用例结束时,回滚实际事务。

这些更改允许它在测试使用事务的方法时表现得像在事务中一样,同时在测试用例完成后保持整个事物的可还原性。

PS -如果有什么我应该做,但没有,让我知道,这样我就可以改进包装类。

最新更新