Я пытаюсь написать некоторые интеграционные тесты для некоторых хранимых процедур и функций SQL-сервера. Я хотел бы иметь базу данных, в которой есть известный набор тестовых данных, а затем переносить каждый тест в транзакцию, откатывая ее по завершении, чтобы тесты были независимыми.Откат вложенных транзакций при модульном тестировании хранимых процедур
Хранимые процедуры/функции делают что-либо из довольно простых запросов присоединения, к сложной фильтрации со многими уровнями соединений, к вставке данных в несколько таблиц.
Существует несколько хранимых процедур, которые фактически используют транзакции - и поэтому их труднее проверить. Я покажу пример общего кода, который выполняется, но имейте в виду, что это обычно будет в двух разных точках (тестовая настройка/срыв и фактическая хранимая процедура). Для этого примера я также использую очень простую временную таблицу:
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», я бы ожидать «АААА» и «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», мы до сих пор получить «КПКГ» в table - он больше не откатывается, потому что транзакция не активна.
Есть ли способ обойти это? Есть ли лучшая стратегия для такого типа тестирования?
Примечание: Я не уверен, что когда-либо когда-либо делаются коды после отката или нет (часть «cccc»), но если это когда-либо произойдет, то преднамеренно или случайно, ломаются странными способами, поскольку неожиданные данные могут быть оставлены из другого теста.
Несколько похож на Nested stored procedures containing TRY CATCH ROLLBACK pattern?, но нет реального решения проблемы, поставленной здесь.
Одна из проблем заключается в том, что требуется, чтобы внутреннее исключение было изменено, то есть внутри проверяемого кода (хранимая процедура). Если кто-то не использует этот шаблон при написании транзакции в базе кода, он все равно может разбить тесты непредсказуемыми способами. Было бы лучше, если бы внешняя транзакция (часть тестовой среды) могла быть изменена, чтобы заставить ее работать для «обычной» транзакции, написанной в тестируемом коде. Спасибо, хотя, в противном случае это хорошая вещь, чтобы знать. – gregmac
@gregmac, TSQL - это то, что есть. Я правильно объяснил, почему у вашего кода есть проблемы и какие у вас есть варианты. –