#asp.net-mvc-3 #unit-testing #architecture #tdd #mocking
#asp.net-mvc-3 #модульное тестирование #архитектура #tdd #издевательство
Вопрос:
Окружающая среда
В моем решении у меня есть три проекта, они:
- Веб (Asp.net MVC4)
- Модель (библиотека классов)
- Тест (тестовый проект)
В модельном проекте есть:
Couple
= Класс
IRepository
= Репозиторий на основе интерфейса
ICoupleRepository
= Пара интерфейсных репозиториев
Implementation
репозиторий = CoupleRepository пара
В тестовом проекте есть:
Поддельная / CoupleRepository
= Поддельная реализация пары репозиториев (внутри папки Fake). CoupleTest
класс пары = Тест
Поведение
Добавив пару в раздел, необходимо изменить некоторые свойства, а также добавить объект пары, а также добавить другие объекты в базу данных.
Я помещаю эту логику в CoupleRepository
(не поддельный) репозиторий в Add
методе, я устанавливаю эти свойства, добавляю пару объектов и два других объекта.
public class CoupleRepository : ICoupleRepository
{
public void Add(Couple couple)
{
couple.Bride.Gender = Gender.Female;
couple.Groom.Gender = Gender.Male;
db.Couples.Add(couple);
db.Users.Add(new User{ CoupleID = couple.Bride.ID });
db.Users.Add(new User{ CoupleID = couple.Groom.ID });
db.SaveChanges();
}
}
Вопрос
В моем тестовом классе, CoupleTest
, также необходимо протестировать добавление этих пользователей и изменение свойств.
Создайте поддельный репозиторий для моего лба, мне это не поможет, действительно нужно протестировать код, который находится в CoupleRepository по умолчанию.
Какой совет вы мне даете?
Где во всем этом участвуют макеты и заглушки?
Где бы эта логика сохранила пару?
Я должен тестировать репозитории? Возможно, идеальным было бы протестировать контроллеры?
Много вопросов, я знаю =)
Я новичок в TDD и не знаю, иду ли я в правильном направлении.
Тестировать репозиторий по умолчанию было бы не идеально, поскольку он обращается к базе данных.
Комментарии:
1. если бы это было на самом деле TDD, разве вы не стали бы сначала писать модульные тесты?
2. Я думаю , что ваши поддельные реализации — это ваши насмешки. Вы просто не называете их так. Однако, чтобы быть действительно полезными макетами, вы хотели бы иметь возможность указывать им вести себя определенным образом, чтобы вы могли тестировать различные варианты поведения.
3. @DavidWick да, то, что ты сказал. Если он не начинает с тестов, он вообще не занимается разработкой, основанной на тестировании.
4. На самом деле это единственная реализация. Я знаю, что поступил неправильно, но не знаю, с чего начать тестирование. Вопрос в том, куда поместить эту реализацию и как ее протестировать?
Ответ №1:
Основная проблема здесь заключается в том, что вы смешиваете разные слои. Репозиторий — это промежуточный уровень между бизнес-логикой и хранилищем. В вашем случае репозиторий выполняет действия, которые являются частью бизнес-логики. Вот почему вы вынуждены имитировать это в своих тестах.
В общем, ваша сущность должна быть полностью сконструирована перед сохранением. Репозиторий должен только сохранять его (возможно, вызывая метод Validate, если вам это нужно).
Этот код:
couple.Bride.Gender = Gender.Female;
couple.Groom.Gender = Gender.Male;
следует перенести в бизнес-логику пары (например, конструктор).
С более глобальной точки зрения, с помощью TDD вы создаете макеты функциональности, которую хотите протестировать. При вашем текущем подходе у вас, вероятно, будет что-то вроде IView -> Couple class -> IRepository
цепочки. Это означает, что, издеваясь над этими интерфейсами, вы намереваетесь протестировать класс Couple (или работу бизнес-логики в целом).
Для тестирования репозитория вам нужна структура, подобная Couple class -> CoupleRepository -> IDatabaseDriver
sequence. С помощью mocking IDatabaseDriver
вы сможете проверять SqlCommands или запросы, сгенерированные реальной реализацией CoupleRepository .
В этом случае вы будете писать тесты типа (очень упрощенный образец):
var driver = new MockDatabaseDriver();
var repo = CoupleRepository(MockDatabaseDriver);
repo.Add(new Couple());
Assert.AreEquals("Insert into COUPLES values ('bride', groom')", driver.SqlQueryText);
Здесь MockDatabaseDriver не выполняет запросы, а просто указывает действия, выполняемые репозиторием.