не может получить доступ к базе данных из нескольких модульных тестов - PullRequest
0 голосов
/ 22 января 2019

У меня была строка подключения и куча моих модульных тестов, использующих ее для проверки логики некоторого класса, который применял к нему некоторые операции 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))

Спасибо!

1 Ответ

0 голосов
/ 22 января 2019

Я также использовал localDb для тестирования в своем веб-приложении, и у меня была похожая проблема.Эта проблема может иногда случиться, если во время отладки вы остановились в промежутке или какой-либо тест столкнулся с каким-либо исключением, и удаление localdb не произошло должным образом.Если это произойдет, то в следующий раз, когда вы начнете запускать test, он не создаст БД (несмотря на проверку ifdbexists) и столкнется с каким-то исключением, как вы упомянули.Чтобы проверить, я добавлял другое имя каждый раз, когда мы запускали набор тестов, так что db создается в начале выполнения теста и сбрасывается после выполнения всех тестов. Поскольку не каждый раз давать разные имена, попробуйте утилизировать localdb вБлок finally, чтобы убедиться, что это происходит даже в случае исключения

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...