В рамках нашего набора тестов, рядом с модульными тестами, которые имитируют все и не требуют подключения к базе данных, у нас также есть тесты интеграции, для которых действительно требуется база данных.
Интеграционные тесты необходимы, потому что мы работаем с большим количеством унаследованного кода, и это дает нам возможность выполнять тесты высокого уровня.
НАСТРОЙКА
База данных - это SQL Server 2008 R2, работающий в системе Windows Server 2008 R2 со всеми последними обновлениями Windows. И для ОС, и для SQL Server.
Виртуальная машина, на которой работает сервер базы данных, является частью нашей инфраструктуры сборки и создается заново, конечно, на основе образа, каждое утро в 6 утра и уничтожается в 10 вечера. Итак, я знаю, что агент и служба SQL Server по сути новый и начинался каждый день. Первая сборка происходит в 7 утра, что дает машине достаточно времени для запуска и загрузки всех служб.
Сервер базы данных настроен так, чтобы разрешать неограниченное количество подключений, и включены именованные каналы и TCP-подключения.
Подключение к базе данных осуществляется са пользователь.
У нас есть урезанный снимок нашей производственной базы данных, a.mdf, который содержит все таблицы, представления, хранимые процедуры и минимальный набор данных, необходимых для выполнения тестов.
При запуске интеграционного теста тестовая установка копирует a.mdf в папку DATA нашей установки SQL Server как b.mdf. Затем b.mdf подключается к базе данных с помощью следующей команды:
CREATE DATABASE Foo ON (FILENAME = N'Path\To\b.mdf') FOR ATTACH
Выполняются тесты, выполняются операции с базой данных, и при тестировании тестового устройства база данных отключается, а файл b.mdf удаляется.
Следующие две команды выполняются отдельно для выполнения отсоединения:
ALTER DATABASE Foo SET SINGLE_USER WITH ROLLBACK IMMEDIATE
EXEC master.dbo.sp_detach_db @dbname = N'Foo'
Итак, на практике у меня есть набор тестовых приборов со следующей компоновкой:
Setup();
Test_1();
Test_2();
Test_3();
TearDown();
Каждая программа установки создает новую базу данных, запускает все тесты и удаляет базу данных, поэтому следующий текстовый набор начинается с чистой, свежей базы данных.
Всего у меня около 50 текстовых приспособлений, каждая из которых содержит 10 тестов. Таким образом, база данных подключается и отключается 50 раз и выполняется около 500 тестов.
ЭТА ПРОБЛЕМА
Последние пару недель я вижу рост количества неудачных сборок, связанных с тестами интеграции. Я знаю, что мои тесты в порядке, потому что вся установка отлично работает на моей локальной машине и на машинах других разработчиков. Это просто сервер сборки, который сообщает о проблеме:
SetUp Error : Namespace.Class.Method
SetUp : System.Data.SqlClient.SqlException : Cannot open database "Foo" requested by the login. The login failed.
Login failed for user 'sa'.
Очевидно, я погуглил, и да, логин правильный. Я знаю это, потому что не всегда один и тот же тест терпит неудачу. Если я запустил весь набор тестов 10 раз, он потерпит неудачу 8 из 10, но тест, который сообщает об ошибке, каждый раз разный. Сообщение об ошибке такое же, в нем говорится, что он не может войти в систему, а иногда также сообщает, на другом конце трубы нет процесса.
Я также проверил, что именованный канал и TCP-соединения включены, я проверил количество разрешенных подключений ... Я проверил файл ERRORLOG, но он не содержит ничего, напрямую связанного с моей базой данных.
Я предполагаю, что по какой-то странной причине это происходит быстро или медленно, и он не может должным образом подключать или отключать базу данных, или это SINGLE_USER
вызов, который вызывает проблему. Из того, что я собрал, если один тест не прошел из-за входа в систему, файл b.mdf не может быть удален, потому что файл, похоже, уже используется.
Итак, мой вопрос: что еще я могу попробовать? Есть ли файл журнала ошибок или конкретное сообщение, которое может дать мне больше информации? Могу ли я что-нибудь сделать, чтобы проверить, были ли присоединение и отсоединение успешными? (Возможно ли, что неудачное отключение вызывает проблему входа в систему?) Является ли операция отключения асинхронной, и, следовательно, возможно ли, что она еще не завершена, когда будет сделан следующий вызов?
Первая проблема: ошибка входа в систему.
Ваша база данных, скорее всего, еще не полностью инициализирована на момент запуска тестов.
Вы должны уловить это в своей процедуре, простой способ сделать это - запросить главную базу данных, чтобы узнать, работает ли целевая база данных.
IF (select name from sys.databases
where name = 'foo' and state_desc = 'ONLINE' and is_in_standby = '0') IS NOT NULL
PRINT 'database not found';
Вторая проблема: на другом конце трубы нет процесса.
Фактическая ошибка часто скрывается, если вы не подключаетесь через TCP / IP.
Вы можете попробовать включить прямые IP-соединения или сосредоточиться на других ошибках, вероятно, они являются причиной этой ошибки.