Как проверить код, связанный с базой данных, с помощью NUnit? - PullRequest
61 голосов
/ 26 ноября 2008

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

Похоже, они решают проблему реализации пользовательского атрибута для NUnit, который обеспечивает возможность отката операций с БД после каждого теста.

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

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

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

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

Ответы [ 5 ]

72 голосов
/ 15 декабря 2008

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 и атрибуты. Я был известен, чтобы понять это неправильно. Интеграционные тесты помогают поймать мою ошибку.

4 голосов
/ 26 ноября 2008

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

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

2 голосов
/ 26 ноября 2008

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

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

1 голос
/ 26 ноября 2008

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

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

(раньше было http://ndbunit.org).

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

0 голосов
/ 07 мая 2010

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

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

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

...