Сбой NUnit [TearDown] - какой процесс обращается к моим файлам? - PullRequest
18 голосов
/ 17 декабря 2008

Окончательное редактирование: Я нашел решение проблемы (внизу вопроса).

У меня проблема с монахиней, которая вызывает у меня горе. Редактировать: на самом деле это больше похоже на проблему 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 должна быть ошибка.

Ответы [ 11 ]

0 голосов
/ 17 декабря 2008

Снос выполняется после каждого теста.

Этот атрибут используется внутри TestFixture для предоставления общего набора функций, которые выполняются после запуска каждого метода тестирования.

Вы должны попытаться удалить их все с помощью TestFixtureTearDown :

    [TestFixtureTearDown]
    public void finish()
    {
        //Delete all file
    }

Возможно, один тест использует файл, который вы пытаетесь удалить в другом тесте. <- [Стюарт] Как я уже говорил в вопросе, это происходит, когда я запускаю только один тест, поэтому это невозможно. </em>

Обновление Вы не даете достаточно информации о том, что вы делаете. Вы пытались очистить весь тестовый файл, используя только один тест в тестовом файле, и попробовать? [Стюарт] Да. Если это работает [Стюарт] (это не так) , тогда у вас есть несколько тестовых проблем (они получают доступ друг к другу). Вам нужно сократить проблему, чтобы найти источник . Тогда, возвращайся сюда, мы поможем тебе. на данный момент это только предположение, что мы можем дать вам. [Стюарт] Я уже сделал эти урезания предложенной вами проблемы, вы обнаружите, что они в моем первоначальном вопросе!

...