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