Окончательное редактирование: Я нашел решение проблемы (внизу вопроса).
У меня проблема с монахиней, которая вызывает у меня горе. Редактировать: на самом деле это больше похоже на проблему SQLite, но я еще не уверен на 100%.
My TestFixture имеет настройку, которая генерирует случайное имя файла, которое используется в качестве базы данных SQLite в каждом из моих тестов.
[Setup]
public void Setup()
{
// "filename" is a private field in my TestFixture class
filename = ...; // generate random filename
}
Каждый из моих тестов использует эту конструкцию в каждом методе, который обращается к базе данных:
[Test]
public void TestMethod()
{
using (var connection = Connect())
{
// do database activity using connection
// I've tried including this line but it doesn't help
// and is strictly unnecessary:
connection.Close();
}
}
private DbConnection Connect()
{
var connection = DbProviderFactories.GetFactory("System.Data.SQLite").CreateConnection();
connection.ConnectionString = "Data Source=" + filename;
connection.Open();
return connection;
}
Так что один вспомогательный метод Connect()
используется всеми методами. Я предполагаю, что конструкция using() { }
вызывает Dispose()
для соединения в конце TestMethod()
и освобождает соединение с файлом базы данных SQLite.
Проблема у меня в методе [TearDown]:
[TearDown]
public void Cleanup()
{
File.Delete(filename); // throws an IOException!
}
С каждым тестом я получаю исключение:
System.IO.IOException: The process cannot access the file 'testdatabase2008-12-17_1030-04.614065.sqlite' because it is being used by another process.
Все тесты не выполняются, когда они попадают в [TearDown], поэтому я получаю каталог, полный временных файлов базы данных (по одному на тест, каждое с другим именем) и целую кучу неудачных тестов.
Какой процесс обращается к файлу? Я не понимаю, как второй процесс может получить доступ к файлу. connection
полностью вышел из области видимости и был Dispose () d к тому времени, когда я пытаюсь удалить файл, поэтому он не может быть чем-то связанным с SQLite. Может ли это?
Обратите внимание, что я получаю тот же результат, если я запускаю все тесты или только один тест.
Обновление: Поэтому я попытался также использовать Dispose () моих объектов DbCommand, поскольку я этого не делал (я предполагал, что любой другой поставщик ADO.NET, который Dispose () использует DbConnection, также Утилизируйте () любые команды в этом соединении.) Теперь они выглядят так:
[Test]
public void TestMethod()
{
using (var connection = Connect())
{
using (var command = connection.CreateCommand())
{
// do database activity using connection
}
}
}
Это не имело никакого значения - строка File.Delete () по-прежнему выбрасывает IOException. : - (
Если я удалю эту строку в [TearDown], тогда все мои тесты пройдут, но у меня останется целая куча временных файлов базы данных.
Другое обновление:
Это работает просто отлично:
var filename = "testfile.sqlite";
using (var connection = BbProviderFactories.GetFactory("System.Data.SQLite").CreateConnection())
{
connection.ConnectionString = "Data Source=" + filename;
connection.Open();
var createCommand = connection.CreateCommand();
createCommand.CommandText =
"CREATE TABLE foo (id integer not null primary key autoincrement, bar text not null);";
createCommand.ExecuteNonQuery();
var insertCommand = connection.CreateCommand();
insertCommand.CommandText = "INSERT INTO foo (bar) VALUES (@bar)";
insertCommand.Parameters.Add(insertCommand.CreateParameter());
insertCommand.Parameters[0].ParameterName = "@bar";
insertCommand.Parameters[0].Value = "quux";
insertCommand.ExecuteNonQuery();
}
File.Delete(filename);
Я не понимаю!
Обновление: Решение найдено:
[TearDown]
public void Cleanup()
{
GC.Collect();
File.Delete(filename);
}
Я запускал модульные тесты через отладчик, и когда запускается метод [TearDown]
, определенно больше нет ссылок на SQLite DbConnection. Принудительный сборщик мусора должен их очистить. В SQLite должна быть ошибка.