Как проверить код, связанный с базой данных с NUnit?

Я хочу написать модульные тесты с помощью NUnit, которые попадают в базу данных. Я хотел бы иметь базу данных в согласованном состоянии для каждого теста. Я думал, что транзакции позволят мне "отменить" каждый тест, поэтому я обыскал и нашел несколько статей с 2004-05 по теме:

Кажется, что они устраняют возможность создания настраиваемого атрибута для NUnit, который создает возможность отката DB-операций после выполнения каждого теста.

Это здорово, но...

  • Эта функция существует где-то в NUnit изначально?
  • Была ли эта техника улучшена за последние 4 года?
  • Это лучший способ проверить код, связанный с базой данных?

Изменить: это не то, что я хочу проверить свой DAL конкретно, это больше, что я хочу проверить фрагменты моего кода, которые взаимодействуют с базой данных. Чтобы эти тесты были "без касания" и повторяемы, было бы здорово, если бы я мог reset базу данных после каждого из них.

Кроме того, я хочу облегчить это в существующий проект, в котором сейчас нет места для тестирования. По этой причине я не могу практически script создать базу данных и данные с нуля для каждого теста.

Ответ 1

NUnit теперь имеет атрибут [Rollback], но я предпочитаю делать это по-другому. Я использую класс TransactionScope. Существует несколько способов его использования.

[Test]
public void YourTest() 
{
    using (TransactionScope scope = new TransactionScope())
    {
        // your test code here
    }
}

Поскольку вы не сказали TransactionScope совершить, он автоматически откатится. Он работает, даже если утверждение терпит неудачу или вызывается какое-то другое исключение.

Другим способом является использование [SetUp] для создания TransactionScope и [TearDown] для вызова Dispose на нем. Он вырезает некоторое дублирование кода, но выполняет то же самое.

[TestFixture]
public class YourFixture
{
    private TransactionScope scope;

    [SetUp]
    public void SetUp()
    {
        scope = new TransactionScope();
    }

    [TearDown]
    public void TearDown()
    {
        scope.Dispose();
    }


    [Test]
    public void YourTest() 
    {
        // your test code here
    }
}

Это так же безопасно, как и оператор using в отдельном тесте, потому что NUnit гарантирует, что TearDown вызывается.

Сказав все, что я действительно думаю, тесты, попавшие в базу данных, на самом деле не являются модульными тестами. Я все еще их пишу, но я считаю их интеграционными тестами. Я по-прежнему вижу в них ценность. Одно место, которое я им часто использую, - это тестирование кода LINQ to SQL. Я не использую конструктора. Я пишу DTO и атрибуты. Мне известно, что все неправильно. Интеграционные тесты помогают поймать мою ошибку.

Ответ 2

Я просто пошел в группу пользователей .NET, и ведущий сказал, что он использовал SQLlite в тестовой настройке и разрыве и использовал опцию в памяти. Он должен был немного подделать связь и явно уничтожить соединение, но каждый раз он будет давать чистую БД.

http://houseofbilz.com/archive/2008/11/14/update-for-the-activerecord-quotmockquot-framework.aspx

Ответ 3

Я бы назвал эти интеграционные тесты, но неважно. То, что я сделал для таких тестов, заключается в том, что мои методы настройки в классе тестов очищают все таблицы, представляющие интерес, перед каждым тестом. Обычно я пишу SQL для этого, чтобы я не использовал тестируемые классы.

Как правило, я полагаюсь на ORM для моего datalayer и, таким образом, я не пишу модульные тесты для многих там. Мне не нужен код unit test, который я не пишу. Для кода, который я добавляю в этот слой, я обычно использую инъекцию зависимостей, чтобы абстрагировать фактическое соединение с базой данных, чтобы при тестировании моего кода он не касался фактической базы данных. Сделайте это в сочетании с насмешливой основой для достижения наилучших результатов.

Ответ 4

Для такого рода тестирования я экспериментировал с NDbUnit (работая совместно с NUnit). Если память служит, это был порт DbUnit с платформы Java. У него было много гладких команд только для того, что вы пытаетесь сделать. Проект, похоже, переместился сюда:

http://code.google.com/p/ndbunit/

(он был http://ndbunit.org).

Источник, по-видимому, доступен по этой ссылке: http://ndbunit.googlecode.com/svn/trunk/

Ответ 5

Рассмотрим создание базы данных script, чтобы вы могли запускать ее автоматически из NUnit, а также вручную для других типов тестирования. Например, если вы используете Oracle, тогда откройте SqlPlus из NUnit и запустите скрипты. Эти сценарии, как правило, быстрее писать и читать легче. Кроме того, очень важно, что запуск SQL от Toad или эквивалент более освещается, чем запуск SQL из кода или переход через ORM из кода. Как правило, я создам настройку и размывание script и помещаю их в методы настройки и удаления.

Независимо от того, следует ли вам проходить через БД вообще из модульных тестов, это еще одно обсуждение. Я считаю, что часто имеет смысл сделать это. Для многих приложений база данных является абсолютным центром действия, логика основана на высоком уровне, а все другие технологии и языки и методы передают призраки. И с ростом функциональных языков мы начинаем понимать, что SQL, как и JavaScript, на самом деле является отличным языком, который был прямо под нашими носами все эти годы.

Так же, как и в стороне, Linq to SQL (который мне нравится в концепции, хотя и никогда не использовался), мне кажется, как способ сделать необработанный SQL из кода, не допуская того, что мы делаем. Некоторые люди любят SQL и знают, что им это нравится, другим нравится и не знают, что им это нравится.:)