我正在嘗試爲某些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