Как проверить код, связанный с базой данных, с помощью NUnit?
Я хочу написать модульные тесты с NUnit, которые попали в базу данных. Я хотел бы иметь базу данных в согласованном состоянии для каждого теста. Я думал, что транзакции позволят мне "отменить" каждый тест, поэтому я искал и нашел несколько статей из 2004-05 на тема:
- http://weblogs.asp.net/rosherove/archive/2004/07/12/180189.aspx
- http://weblogs.asp.net/rosherove/archive/2004/10/05/238201.aspx
- http://davidhayden.com/blog/dave/archive/2004/07/12/365.aspx
- http://haacked.com/archive/2005/12/28/11377.aspx
Они, похоже, разрешаются вокруг реализации пользовательского атрибута для NUnit, который строит возможность отката операций БД после выполнения каждого теста.
Это здорово, но...
- это функциональность существует где-то в Нанит изначально?
- была ли эта техника улучшена за последние 4 года?
- Это все еще лучший способ проверить код, связанный с базой данных?
Edit: это не то, что я хочу проверить свой DAL конкретно, это больше, что я хочу, чтобы проверить куски моего кода, которые взаимодействуют с база данных. Чтобы эти тесты были "без касания" и повторялись, было бы здорово, если бы я мог сбросить базу данных после каждого из них.
кроме того, я хочу облегчить это в существующий проект, который не имеет места для тестирования на данный момент. По этой причине я практически не могу создать сценарий базы данных и данных с нуля для каждого теста.
5 ответов:
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. Я не использую дизайнера. Я рукой пишу и атрибуты ДТО по. Я, как известно, ошибаюсь. Интеграционные тесты помогают поймать мою ошибку.
Я просто пошел в группу пользователей .NET, и ведущий сказал, что он использовал SQLlite в тестовой установке и демонтаже и использовал опцию in memory. Он должен был немного подделать соединение и явно уничтожить соединение, но это дало бы чистый DB каждый раз.
http://houseofbilz.com/archive/2008/11/14/update-for-the-activerecord-quotmockquot-framework.aspx
для такого рода тестирования я экспериментировал с NDbUnit (работая совместно с NUnit). Если память не изменяет, это был порт DbUnit с платформы Java. У него было много гладких команд для того, что вы пытаетесь сделать. Проект, кажется, переехал сюда:
http://code.google.com/p/ndbunit/
(раньше это было в http://ndbunit.org).
источник, кажется, доступен через это ссылка на сайт: http://ndbunit.googlecode.com/svn/trunk/
Я бы назвал эти интеграционные тесты, но это не важно. То, что я сделал для таких тестов, - это мои методы настройки в тестовом классе очистить все интересующие таблицы перед каждым тестом. Я обычно вручную пишу SQL, чтобы сделать это, чтобы я не использовал тестируемые классы.
Как правило, я полагаюсь на ORM для моего datalayer, и поэтому я не пишу модульные тесты для многого там. Я не чувствую необходимости в модульном тестовом коде, который я не пишу. Для кода, который я добавляю в слой, я обычно используйте инъекцию зависимостей, чтобы абстрагировать фактическое соединение с базой данных, чтобы при тестировании моего кода он не касался фактической базы данных. Сделайте это в сочетании с издевательской структурой для достижения наилучших результатов.
рассмотрите возможность создания сценария базы данных, чтобы вы могли запускать его автоматически из NUnit, а также вручную для других типов тестирования. Например, если вы используете Oracle, то запустите SqlPlus из NUnit и запустите сценарии. Эти сценарии, как правило, быстрее писать и легче читать. Кроме того, очень важно, что запуск SQL из жабы или эквивалента более освещен, чем запуск SQL из кода или прохождение ORM из кода. Как правило, я создам как сценарий установки, так и сценарий демонтажа и поместите их в методы настройки и демонтажа.
следует ли вам вообще проходить через БД из модульных тестов-это еще одно обсуждение. Я считаю, что это часто имеет смысл сделать. Для многих приложений база данных является абсолютным центром действия, логика сильно настроена, и все другие технологии, языки и методы передают призраки. И с ростом функциональных языков мы начинаем понимать, что SQL, как и JavaScript, на самом деле является отличным языком что было под носом все эти годы.
Так же, как в стороне, Linq to SQL (который мне нравится в концепции, хотя я никогда не использовал) почти кажется мне способом сделать raw SQL из кода, не признавая того, что мы делаем. Некоторые люди любят SQL и знают, что им это нравится, другие любят его и не знают, что им это нравится. :)