2008-11-26 4 views
58

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

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

Это замечательно, но ...

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

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

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

ответ

67

NUnit теперь имеет [Откат] атрибут, но я предпочитаю делать это по-другому. Я использую класс 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 
    } 
} 

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

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

1

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

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

+0

К сожалению, этот подход не применим для моих проектов (сотни таблиц, процедур, концертов данных). Это слишком высокое трение, чтобы оправдать существующий проект. – 2008-11-26 16:11:35

+0

Но ваши юнит-тесты должны быть разбиты на более мелкие, более сфокусированные классы, которые не касаются всех таблиц. Вам нужно иметь дело только с таблицами, которые затрагивает этот конкретный класс. – tvanfosson 2008-11-26 16:13:44

3

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

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

1

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

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

(он будет использоваться в http://ndbunit.org).

источник, как представляется, будет доступна по этой ссылке: http://ndbunit.googlecode.com/svn/trunk/

0

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

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^