我正在尝试为某些SQL Server存储过程和函数编写一些集成测试。我希望有一个数据库中包含一组已知的测试数据,然后将每个测试包装在一个事务中,并在完成时将其回滚,以便测试实际上是独立的。在单元测试存储过程时回滚嵌套事务
存储过程/函数执行任何操作,从相当简单的连接查询到复杂的多层连接过滤,以及将数据插入多个表。
有一些实际使用事务的存储过程 - 所以这些更难以测试。我将展示一个被执行的整体代码的例子,但请记住,这通常会出现在两个不同的位置(测试设置/拆卸以及实际的存储过程)。对于此示例,我还使用一个非常简单的临时表:
CREATE TABLE #test (
val nvarchar(500)
)
例子:
-- for this example, just ensuring that the table is empty
delete from #test
go
-- begin of test setup code --
begin transaction
go
-- end of test setup code --
-- begin of code under test --
insert into #test values('aaaa')
begin transaction
go
insert into #test values('bbbbb')
rollback transaction
go
insert into #test values('ccccc')
-- Example select #1:
select * from #test
-- end of code under test --
-- begin of test teardown --
rollback transaction
go
-- end of test teardown
-- checking that #temp is still empty, like it was before test
-- Example select #2:
select * from #test
这里的问题是,在“实例选择#1”,我希望“AAAA”和“cccc”放在表中,但实际上只有“cccc”在表中,因为SQL Server实际上会回滚所有事务(请参阅http://abdulaleemkhan.blogspot.com/2006/07/nested-t-sql-transactions.html)。此外,第二回滚导致错误,虽然这可以被避免:
-- begin of test teardown --
if @@trancount > 0
begin
rollback transaction
end
go
-- end of test teardown
它并不能解决真正的问题:在“示例选择#2”中,我们仍然可以得到“CCCC”的表 - 它不再被回滚,因为没有事务处于活动状态。
有没有办法解决这个问题?这种类型的测试有更好的策略吗?注:我不确定代码库是否在回滚之后执行了任何操作(插入'cccc'部分) - 但是如果它有意或无意地执行,那么测试可能会因为意外的数据可能会从另一个测试中遗留下来,所以以奇怪的方式突破
有点类似于Nested stored procedures containing TRY CATCH ROLLBACK pattern?但这里提出的问题没有真正的解决方案。
这样做的一个问题是它需要修改内部异常 - 也就是被测代码(存储过程)中的一个。如果有人在代码库中编写事务时不使用这种模式,它仍然可能以不可预知的方式破坏测试。如果可以修改外部事务(测试框架的一部分)以使其适用于在正在测试的代码中编写的“常规”事务,那将会更好。不过谢谢,否则这是一件很好的事情要知道。 – gregmac 2010-02-22 22:40:53
@gregmac,TSQL就是这样。我正确地解释了为什么你的代码有问题,以及你有什么选择。 – 2010-02-23 12:46:44