【问题标题】:Using SQL rollback after a test case, but the method being tested uses commit在测试用例之后使用 SQL 回滚,但被测试的方法使用提交
【发布时间】:2014-06-26 16:02:38
【问题描述】:

我正在尝试为我们应用的一种数据库访问方法编写单元测试。我们有一个专用的测试数据库(实时数据库的定期转储/副本)。通常每个测试用例都在单个事务中运行,然后回滚。我们通过在测试用例之前使用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);
}

【问题讨论】:

    标签: java postgresql jdbc junit automated-tests


    【解决方案1】:

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

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

    【讨论】:

    • 您无需提交测试和确认更改,只需在回滚之前使用相同的连接来确认任何用于确认更改的加载代码。
    • @MartinCarney - 那么测试并不是真正测试数据库,只是孤立的代码逻辑。如果您有一个测试数据库,那么您没有理由不提交,并且您会遇到这样的问题,您的代码必须适应测试用例,而不是相反。如果您只是想测试逻辑,只需使用内存数据库或一组模拟,但您将自己敞开心扉去探索。
    【解决方案2】:

    问我的办公室同事是否有任何想法。有人建议嘲笑它(使用 Mockquito),这让我找到了一个更好的选择。我正在为Connection 创建一个包装器,它扩展Connection 并像普通连接一样,但是当使用它的事务相关方法时,它的行为会有所不同。

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

    具体来说:

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

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

    PS - 如果有什么我应该做但没有做的事情,请告诉我,以便我改进包装类。

    【讨论】:

      猜你喜欢
      • 2020-02-10
      • 2017-08-05
      • 2015-06-19
      • 1970-01-01
      • 2014-11-14
      • 1970-01-01
      • 2022-10-05
      • 2021-06-13
      • 1970-01-01
      相关资源
      最近更新 更多