Я пытаюсь выяснить, как правильно и эффективно unit test мой проект MVC Asp.net. Когда я начал этот проект, я купил Pro ASP.Net MVC, и с этой книгой я узнал о TDD и модульном тестировании. Увидев примеры и тот факт, что я работаю инженером-программистом в QA в своей нынешней компании, я был поражен тем, насколько удивительным TDD казалось. Поэтому я начал работать над своим проектом и пошел на gung ho для написания модульных тестов для моего уровня базы данных, бизнес-уровня и контроллеров. Все было unit test до внедрения. Сначала я подумал, что это потрясающе, но потом все стало идти вниз.
Вот проблемы, с которыми я начал сталкиваться:
-
Я закончил писать код приложения, чтобы можно было выполнить модульные тесты. Я не имею в виду это в хорошем смысле, так как в моем коде был сломан, и мне пришлось исправить его, чтобы пройти unit test. Я имею в виду, что абстрагирование базы данных до макетной базы данных невозможно из-за использования linq для извлечения данных (с использованием шаблона общего шаблона репозитория).
Причина в том, что с linq- > sql или linq- > сущностями, которые вы можете делать, просто:
var objs = select p from _container.Projects select p.Objects;
Однако, если вы издеваетесь над уровнем базы данных, чтобы этот linq прошел unit test, вы должны изменить linq как
var objs = select p from _container.Projects join o in _container.Objects on o.ProjectId equals p.Id select o;
Это не только означает, что вы меняете логику приложения, так что вы можете unit test его, но вы делаете свой код менее эффективным с единственной целью проверки, и избавление от множества преимуществ с использованием ORM в первую очередь.
Кроме того, поскольку многие идентификаторы для моих моделей являются сгенерированными базами данных, мне пришлось писать дополнительный код для обработки тестов без базы данных, поскольку идентификаторы никогда не генерировались, и мне приходилось обрабатывать эти случаи для модульных тестов чтобы пройти, но они никогда не появятся в реальных сценариях.
Таким образом, я закончил тем, что выбрал тестирование модуля базы данных.
-
Написание модульных тестов для контроллеров было легко, пока я возвращал представления. Однако основная часть моего приложения (и того, который больше всего выиграет от модульного тестирования) - это сложное веб-приложение ajax. По разным причинам я решил изменить приложение на возвращение просмотров, чтобы вернуть JSON с данными, которые мне нужны. После этого мои модульные тесты стали чрезвычайно болезненными для записи, так как я не нашел хорошего способа написать модульные тесты для нетривиального json.
После того, как я ударил голову и потратил массу времени, пытаясь найти хороший способ для unit test JSON, я сдался и удалил все тесты моего контроллера (все действия контроллера сосредоточены на этой части приложения, далеко).
-
Итак, наконец, я остался с тестированием уровня сервиса (BLL). Сейчас я использую EF4, однако у меня была эта проблема с linq- > sql. Я решил сделать первый подход к модели EF4, потому что для меня имеет смысл сделать это таким образом (определите мои бизнес-объекты и дайте структуре понять, как перевести ее в бэкэнд sql). Это было хорошо в начале, но теперь это становится громоздким из-за отношений.
Например, у меня есть объекты
Project
,User
иObject
. Один объект должен быть связан с проектом, и проект должен быть связан с пользователем. Это не только правило конкретной базы данных, но и мои бизнес-правила. Однако, скажем, я хочу сделать unit test, что я могу сохранить объект (для простого примера). Теперь я должен сделать следующий код, чтобы убедиться, что сработало:User usr = new User { Name = "Me" }; _userService.SaveUser(usr); Project prj = new Project { Name = "Test Project", Owner = usr }; _projectService.SaveProject(prj); Object obj = new Object { Name = "Test Object" }; _objectService.SaveObject(obj); // Perform verifications
Есть много проблем, связанных с необходимостью делать все это только для выполнения одного unit test. С этим связано несколько проблем.
- Для начала, если я добавлю новую зависимость, например, все проекты должны принадлежать категории, я должен войти в КАЖДОЕ одиночное unit test, которое ссылается на проект, добавляет код для сохранения категории, а затем добавляет код для добавления категории к проекту. Это может быть ОГРОМНОЕ усилие в пути к очень простому изменению бизнес-логики, и все же почти ни один из модульных тестов, которые я буду изменять для этого требования, на самом деле не предназначен для проверки этой функции/требований.
- Если я затем добавлю проверки в метод SaveProject, чтобы проекты не могли быть сохранены, если у них нет имени с не менее чем 5 символами, я должен пройти через каждый объект и проект unit test, чтобы убедиться, что новое требование не приводит к сбою каких-либо несвязанных модульных тестов.
- Если есть проблема в методе
UserService.SaveUser()
, это приведет к сбою всех тестов проекта и объекта, и причина этого не будет сразу заметна без необходимости выкапывать исключения.уль >
Таким образом, я удалил все модульные тесты уровня сервиса из моего проекта.
Я мог бы продолжать и продолжать, но до сих пор я не видел никакого способа для модульного тестирования, чтобы фактически помочь мне и не мешать мне. Я могу видеть конкретные случаи, когда я могу и, вероятно, буду выполнять модульные тесты, например, чтобы убедиться, что мои методы проверки данных работают правильно, но этих случаев мало и далеко. Некоторые из моих проблем, вероятно, могут быть смягчены, но не без добавления дополнительных слоев в мое приложение и тем самым сделать больше ошибок, чтобы я мог unit test.Таким образом, у меня нет модульных тестов, оставшихся в моем коде. К счастью, я сильно использую контроль источника, поэтому я могу вернуть их, если понадобится, но я просто не вижу смысла.
Всюду в Интернете я вижу, как люди говорят о том, насколько велики тесты TDD, и я говорю не только о фанатичных людях. Немногие, кто отклоняет тесты TDD/Unit, дают плохие аргументы, утверждая, что они более эффективны для отладки вручную через среду IDE или что их навыки кодирования поразительны, что им это не нужно. Я признаю, что оба эти аргумента являются полными быками, особенно для проекта, который должен поддерживаться несколькими разработчиками, но любые действительные опровержения для TDD кажутся немногочисленными и далеко друг от друга.
Итак, точка этого сообщения - спросить, я просто не понимаю, как использовать TDD и автоматические модульные тесты?