- PVSM.RU - https://www.pvsm.ru -
Если юнит-тесты работают с базой и меняют её — что сделать, чтобы результаты прогона были повторимы?
Ответ — чистить базу перед тестом. Но хочется иметь какой то набор данных в базе, чтобы каждый раз его туда не записывать из тестов (будем называть такие данные “базовым набором”). Таким образом мы упростим сами тесты и их setup во много раз.
Как это можно реализовать? В голову приходят несколько вариантов:
(какие ещё варианты предложите вы?)
Поработав некоторое время с подобным решением на базе “скрипта очистки”, было решено попробовать что то новое. Этим новым стал вариант с “резервной копией”.
Замечу, что моментальные снимки мне нравятся больше, но их нет в MS Sql Express, а я работаю с ним.
Весь подход разрабатывался для платформы .Net и MS Sql server.
Первые пробы выявили следующие проблемы:
Итак, пришло время реализации.
Получается, перед тестом, в SetUp будут выполнятся скрипты по удалению лишних подключений к БД, а потом — восстановление из резервной копи.
Скрипт отключения пользователей:
DECLARE <hh user=twho> TABLE(
SPID int ,
ecid int ,
[STATUS] NVARCHAR(64) ,
[Loginame] NVARCHAR(64) ,
[HostName] NVARCHAR(64) ,
[Blk] int ,
[DBName] NVARCHAR(64) ,
cmd NVARCHAR(64),
request_id INT)
INSERT INTO <hh user=twho> EXEC SP_WHO
DECLARE spid_cursor CURSOR FOR
SELECT SPID FROM <hh user=twho>
WHERE DBName = <hh user=dbname>
OPEN spid_cursor
DECLARE <hh user=SpidToClose> INT
FETCH NEXT FROM spid_cursor
INTO <hh user=SpidToClose>
WHILE @<hh user=FETCH_STATUS> = 0
BEGIN
IF @<hh user=SPID> <> <hh user=SpidToClose>
BEGIN
-- kill не может работать с параметром.
declare <hh user=str> varchar(32)
set <hh user=str>='KILL ' + cast(<hh user=SpidToClose> as varchar(16))
exec(<hh user=str>)
END
FETCH NEXT FROM spid_cursor
INTO <hh user=SpidToClose>
END
CLOSE spid_cursor;
DEALLOCATE spid_cursor;
Скрипт по откату базы:
USE master
RESTORE DATABASE [FSID_test] FROM DISK = N'c:BackupPathHereBackupNameHere.bak' WITH FILE = 2
Код для вызова из SetUp теста
public static void RevertDb()
{
// если кто то юзает базу - мы не сможем её откатить. закроем все чужие подключения
var sb = new SqlConnectionStringBuilder(Utilities.ConnectionDb) { ConnectTimeout = 2, ApplicationName = "FSID Tests, clearing" };
using (var con = new SqlConnection(sb.ToString()))
{
con.Open();
using (var cmd = con.CreateCommand())
{
cmd.CommandText = Utilities.CommandKillAllConectionsToDb;
cmd.Parameters.AddWithValue("<hh user=dbname>", sb.InitialCatalog);
var result = cmd.ExecuteScalar();
}
}
// дотнет не закрывает подключения насовсем - он их в кэше приберегает, зараза. От этого откат базы ломается. Почистим кэш.
SqlConnection.ClearAllPools();
using (var con = new SqlConnection(sb.ToString()))
{
con.Open();
using (var cmd = con.CreateCommand())
{
cmd.CommandText = Utilities.CommandRevertTestDb;
cmd.ExecuteScalar();
}
}
}
Сейчас всё выглядит довольно просто, но в процессе пришлось решить несколько мелких проблем, с которыми раньше на сталкивался:
Итак, попробовав всё это на практике, можно смело утверждать — подход жизнеспособен и удобен. Особенности:
Автор: Alexus1024
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/net/9430
Нажмите здесь для печати.