Вопрос

Прошлым летом я разрабатывал базовое CRUD-приложение ASP.NET/SQL Server, и модульное тестирование было одним из требований.Я столкнулся с некоторыми проблемами, когда пытался протестировать базу данных.Насколько я понимаю, модульные тесты должны быть:

  • лицо без гражданства
  • независимы друг от друга
  • повторяемо с теми же результатами, т.е.никаких стойких изменений

Кажется, что эти требования противоречат друг другу при разработке базы данных.Например, я не могу протестировать Insert(), не убедившись, что строки, которые нужно вставить, еще отсутствуют, поэтому мне нужно сначала вызвать Delete().Но что, если их еще нет?Тогда мне нужно будет сначала вызвать функцию Exists().

Мое окончательное решение включало в себя очень большие функции настройки (фу!) и пустой тестовый пример, который запускался первым и указывал, что установка прошла без проблем.Это значит жертвовать независимостью тестов при сохранении их безгражданства.

Другое решение, которое я нашел, — это обернуть вызовы функций в транзакцию, которую можно легко откатить, например XtUnit Роя Ошерова.Эта работа, но она включает в себя другую библиотеку, другую зависимость, и кажется слишком тяжелым решением рассматриваемой проблемы.

Итак, что же сделало сообщество SO, столкнувшись с этой ситуацией?


tgmdbm сказал:

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

Итак, если я правильно прочитал, на самом деле нет никакого способа эффективно модульное тестирование уровня доступа к данным.Или «модульное тестирование» уровня доступа к данным будет включать в себя тестирование, скажем, SQL/команд, генерируемых классами, независимо от фактического взаимодействия с базой данных?

Это было полезно?

Решение

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

Вы обычно не единица протестируйте базу данных.Обычно вы включаете базу данных в интеграция тесты.

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

Другие советы

ДБунит

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

Обычное решение внешних зависимостей в модульных тестах — использование фиктивных объектов, то есть библиотек, имитирующих поведение реальных объектов, на которых вы тестируете.Это не всегда просто и иногда требует некоторой изобретательности, но есть несколько хороших (бесплатных) макетных библиотек для .Net, если вы не хотите «создавать свои собственные».На ум сразу приходят два:

Носорог издевается тот, который имеет довольно хорошую репутацию.

НМок Другой.

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

В макетах базы данных это означает «издевательство» над вашим собственным уровнем доступа к БД с помощью объектов, которые возвращают готовые объекты таблицы, строки или набора данных для ваших модульных тестов.

Там, где я работаю, мы обычно создаем собственные макеты библиотек с нуля, но это не значит, что вы должны это делать.

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

я очень рекомендую Мокк как ваша насмешливая структура.Я использовал Rhino Mocks и NMock.Moq был очень простым и решал все проблемы, которые у меня возникали с другими фреймворками.

У меня был тот же вопрос, и я пришел к тем же основным выводам, что и другие ответившие здесь:Не беспокойтесь о модульном тестировании фактического уровня связи с БД, но если вы хотите выполнить модульное тестирование функций вашей модели (чтобы убедиться, что они правильно извлекают данные, правильно их форматируют и т. д.), используйте какой-нибудь фиктивный источник данных и установочные тесты. для проверки извлекаемых данных.

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

Шаблоны модульных тестов

Я объяснил технику, которую использовал в этой самой ситуации. здесь.

Основная идея состоит в том, чтобы опробовать каждый метод в вашем DAL - подтвердить свои результаты - и после завершения каждого теста выполнить откат, чтобы ваша база данных была чистой (без ненужных/тестовых данных).

Единственная проблема, которую вы можете не найти «отличной», заключается в том, что я обычно провожу весь тест CRUD (не чистый с точки зрения модульного тестирования), но этот интеграционный тест позволяет вам увидеть ваш код сопоставления CRUD + в действии.Таким образом, если оно сломается, вы узнаете об этом до того, как запустите приложение (сэкономит мне массу работы, когда я пытаюсь работать быстро).

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

Тестирование уровня данных и базы данных вместе оставляет несколько сюрпризов для последующего в проекте.Но тестирование на базу данных имеет свои проблемы, основной из которых вы тестируете против государства, разделяемого многими тестами.Если вы вставляете строку в базу данных в одном тесте, следующий тест также сможет увидеть эту линию.
Что вам нужно, так это способ откатить изменения, внесенные вами в базу данных.
А Область транзакции Класс достаточно умный, чтобы справиться с очень сложными транзакциями, а также вложенные транзакции, в которых ваш код под тестовыми вызовами совершает свою собственную локальную транзакцию.Вот простой кусок кода, который показывает, как легко добавить возможности отката к вашим тестам:

    [TestFixture]
    public class TrannsactionScopeTests
    {
        private TransactionScope trans = null;

        [SetUp]
        public void SetUp()
        {
            trans = new TransactionScope(TransactionScopeOption.Required);
        }

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

        [Test]
        public void TestServicedSameTransaction()
        {
            MySimpleClass c = new MySimpleClass();
            long id = c.InsertCategoryStandard("whatever");
            long id2 = c.InsertCategoryStandard("whatever");
            Console.WriteLine("Got id of " + id);
            Console.WriteLine("Got id of " + id2);
            Assert.AreNotEqual(id, id2);
        }
    }

Если вы используете LINQ to SQL в качестве ORM, вы можете генерировать базу данных «на лету» (при условии, что у вас есть достаточный доступ из учетной записи, используемой для модульного тестирования).Видеть http://www.aaron-powell.com/blog.aspx?id=1125

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top