У меня была строка подключения и куча моих модульных тестов, использующих ее для проверки логики некоторого класса, который применял к нему некоторые операции CRUD. Таким образом, я передавал это как частное постоянное поле в тестовом классе и делился им со своими тестами. Все отлично работало!
Но потом я понял, что должен сделать это как интеграционное тестирование. Поэтому я решил использовать статический вспомогательный класс для создания базы данных через сеанс, чтобы тесты работали с ней, а затем отбросили.
Класс следующий:
public static class LocalDB
{
public const string DB_DIRECTORY = "Data";
public static string GetLocalDB(string dbName, bool deleteIfExists = false)
{
try
{
var outputFolder = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), DB_DIRECTORY);
var mdfFilename = dbName + ".mdf";
var dbFileName = Path.Combine(outputFolder, mdfFilename);
var logFileName = Path.Combine(outputFolder, $"{dbName}_log.ldf");
if (!Directory.Exists(outputFolder))
{
Directory.CreateDirectory(outputFolder);
}
if (File.Exists(dbFileName) && deleteIfExists)
{
if (File.Exists(logFileName)) File.Delete(logFileName);
File.Delete(dbFileName);
CreateDatabase(dbName, dbFileName);
}
else if (!File.Exists(dbFileName))
{
CreateDatabase(dbName, dbFileName);
}
var connectionString = string.Format(@"Data Source=(LocalDB)\v11.0;AttachDBFileName={1};Initial Catalog={0};Integrated Security=True;", dbName, dbFileName);
CreateTable(connectionString, "Cpa", dbName);
return connectionString;
}
catch(Exception ex)
{
throw;
}
}
public static bool CreateDatabase(string dbName, string dbFileName)
{
try
{
var connectionString = @"Data Source=(LocalDB)\v11.0;Initial Catalog=master;Integrated Security=True";
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
var cmd = connection.CreateCommand();
DetachDatabase(dbName);
cmd.CommandText = string.Format("CREATE DATABASE {0} ON (NAME = N'{0}', FILENAME = '{1}')", dbName, dbFileName);
cmd.ExecuteNonQuery();
cmd.Dispose();
}
return File.Exists(dbFileName);
}
catch
{
throw;
}
}
public static bool DetachDatabase(string dbName)
{
try
{
var connectionString = $@"Data Source=(LocalDB)\v11.0;Initial Catalog=master;Integrated Security=True";
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
var cmd = connection.CreateCommand();
cmd.CommandText = $"exec sp_detach_db '{dbName}'";
cmd.ExecuteNonQuery();
cmd.Dispose();
return true;
}
}
catch(Exception ex)
{
return false;
}
}
public static bool CreateTable(string connectionString, string tableName, string dbName)
{
connectionString = connectionString.Replace("master", dbName);
try
{
using (var connection = new SqlConnection(connectionString))
{
var createTableQuery = $@"CREATE TABLE {tableName}(
CrmId nvarchar(50) NOT NULL,
Service nvarchar(25) NOT NULL,
RecurringReference nvarchar(50),
ExpiryDate datetime,
CardNumber nvarchar(50),
Enabled bit,
Brand nvarchar(50),
CpaType nvarchar(50),
Channel nvarchar(50)
);";
var command = new SqlCommand(createTableQuery, connection);
connection.Open();
var reader = command.ExecuteReader();
reader.Dispose();
return true;
}
}
catch (Exception ex)
{
return false;
}
}
}
Я вызывал метод GetLocalDB в поле инициализации ctor amd моего тестового класса.
После этого у меня появляется следующая ошибка: «процесс не может получить доступ к файлу blah log.ldf , поскольку он используется другим процессом»
!!! Во всех тестах использовалась одна и та же строка подключения, я понятия не имею, что пошло не так. Это не может быть ошибка модульных тестов, поскольку все, что я изменил, это строка подключения (была для уже существующей базы данных -> изменена на временную локальную (класс LocalDb))
Спасибо!