使用 tSQLt 测试时如何回滚事务
我最近正在调用一个代码中包含 rasierror 的过程。 raiserror 位于 try catch 块中。 BEGIN TRAN 也位于 raiserror 之后的同一个 try catch 块中。 Catch 块旨在在事务中发生错误时回滚事务。它执行此操作的方法是检查 @@TRANCOUNT 是否大于 0 我知道它已经启动了一个事务并且需要回滚。使用 tSQLt 进行测试时,@@TRANCOUNT 始终 >0,因此如果它遇到 CATCH 块,则会执行 ROLLBACK 并且 tSQLt 失败(因为 tSQLt 正在事务中运行)。当我发生错误并且运行 CATCH 块时,tSQLt 总是无法通过测试。我无法测试 raiserror 的正确处理。您将如何创建一个可能回滚事务的测试用例?
I recently was calling a procedure that contained a rasierror in the code. The raiserror was in a try catch block. Also a BEGIN TRAN was in the same try catch block after the raiserror. The Catch block is designed to ROLLBACK the transaction if the error occurred in the transaction. The way it does this is to check the @@TRANCOUNT if it is greater that 0 I know that it had started a transaction and needs to ROLLBACK. When testing with tSQLt the @@TRANCOUNT is always >0 so if it ever hits the CATCH Block the ROLLBACK is executed and tSQLt fails (because tSQLt is running in a transaction). When I rasie an error and the CATCH block is run tSQLt always fails the test. I have no way to test for the correct handling of the raiserror. How would you create a test case that can potentially ROLLBACK a transaction?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
正如您所提到的,tSQLt 在自己的事务中运行每个测试。要跟踪正在发生的情况,需要在测试完成时同一事务仍然处于打开状态。 SQL Server 不支持嵌套事务,因此您的过程会回滚所有内容,包括框架为当前测试存储的状态信息。此时 tSQLt 只能假设发生了非常糟糕的事情。因此,它将测试标记为错误。
SQL Server 本身不鼓励在过程内进行回滚,如果在打开的事务中调用该过程,则会抛出错误。有关处理这种情况的方法和一些其他信息,请查看我的关于如何回滚的博客文章程序。
As you mentioned, tSQLt runs every test in its own transaction. To keep track of what is going on is relies on that same transaction to be still open when the test finishes. SQL Server does not support nested transactions, so your procedure rolls back everything, including the status information the framework stored for the current test. At that point tSQLt can only assume that something really bad happened. It therefore marks the test as errored.
SQL Server itself discourages a rollback inside a procedure, by throwing an error if that procedure was called within an open transaction. For ways to deal with this situation and some additional info check out my blog post about how to rollback in procedures.
当我刚刚阅读 tSQLt 时,这是当我了解事务中运行的每个测试时首先想到的问题之一。由于我的一些存储过程确实启动事务,有些甚至使用嵌套事务,这可能变得具有挑战性。根据我对嵌套事务的了解,如果您应用以下规则,您可以使代码免受持续错误检查的影响,并且仍然可以优雅地处理错误。
请牢记这些规则,这里有一个 proc 实现和测试代码的示例来测试它。
As I'm just reading up on tSQLt this was one of the first questions that came to mind when I've learned each test ran in a transactions. As some of my stored procedures do start transaction, some even use nested transactions, this can become challenging. What I've learned about nested transactions, if you apply the following rules you can keep your code clean of constant error checking and still handle errors gracefully.
Keeping those rules in mind here is an example of a proc implementation and test code to test it.
最好在
BEGIN TRANSACTION
之后使用BEGIN TRY
块。当我遇到类似问题时我就这样做了。这更符合逻辑,因为在 CATCH 块中我检查了 IF @@TRANCOUNT > 0 回滚。如果在BEGIN TRANSACTION
之前引发另一个错误,则不需要检查此条件。在这种情况下,您可以测试您的RAISERROR
功能。Better to use a
BEGIN TRY
block afterBEGIN TRANSACTION
. I did this when I had a similar problem. This is more logical, because inCATCH
block I checkedIF @@TRANCOUNT > 0 ROLLBACK
. This condition doesn't need to be checked if another error is raised beforeBEGIN TRANSACTION
. And in this case you can test yourRAISERROR
functionality.对上述两个答案+1。
但是,如果您不想使用 TRY .. CATCH,请尝试以下代码。
-----
行之间的部分代表测试,上方和下方代表 tSQLt,在调用您的测试之前和之后。正如您所看到的,无论错误是否发生,tSQLt 在调用测试之前启动的事务仍然存在,正如它所期望的那样。 @@TRANSCOUNT 仍然是 1您可以注释掉 RAISERROR 来尝试是否引发异常。
感谢 http://www.blackwasp.co.uk/SQLSavepoints.aspx< 中的信息和代码/a>
+1 to both the above answers.
However, if you don't want to use TRY .. CATCH, please try the following code. The part between the lines
-----
represents the test, and above and below that represents tSQLt, before and after it calls your test. As you can see, the transaction started by tSQLt before calling the test, is still in place, as it expects, whether or not the error occurs. @@TRANSCOUNT is still 1You can comment out the RAISERROR to try it with and without the exception being raised.
With acknowledgement to information and code at http://www.blackwasp.co.uk/SQLSavepoints.aspx