Правильное издевательство над универсальным методом

#c# #unit-testing #mocking #moq

#c# #модульное тестирование #издевательство #moq

Вопрос:

Новое для Moq и издевательства в целом. Тестирование класса, который имеет универсальный RepositoryFactory и использует несколько своих репозиториев. Должен ли я инициализировать так или есть какой-то лучший способ?

 Mock<IRepositoryFactory> factory;
        Mock<IRepository<User>> userRepository;
        Mock<IRepository<Role>> roleRepository;
        Mock<IRepository<Meeting>> meetingRepository;

        [TestInitialize()]
        public void MyTestInitialize()
        {
            meetingRepository = new Mock<IRepository<Meeting>>();
            //some meeting setup

            userRepository = new Mock<IRepository<User>>();
            //some user setup

            roleRepository = new Mock<IRepository<Role>>();
            //some role setup

            factory = new Mock<IRepositoryFactory>();
            factory.Setup(f => f.CreateRepository<Meeting>()).Returns(meetingRepository.Object);
            factory.Setup(f => f.CreateRepository<User>()).Returns(userRepository.Object);
            factory.Setup(f => f.CreateRepository<Role>()).Returns(roleRepository.Object);
  

Обратите внимание, что у меня могло бы быть больше mcuh.

здесь я делаю все это в своем методе инициализации, но, думаю, я должен делать это индивидуально или что-то еще.

Ответ №1:

Я не знаю способа настройки f => f.CreateRepository<T>() , учитывая, что настройки вашего репозитория могут отличаться для каждого T . Помимо этого, вы можете использовать функциональные спецификации (см. Это Сообщение в блоге ), что делает вещи немного чище.

Для вашего примера это будет выглядеть так:

 var factory = Mock.Of<IRepositoryFactory>(
    x => 
    x.CreateRepository<Meeting>() == Mock.Of<IRepository<Meeting>>() amp;amp;
    x.CreateRepository<Role>() == Mock.Of<IRepository<Role>>() amp;amp;
    x.CreateRepository<User>() == Mock.Of<IRepository<User>>()
    );
  

Ответ №2:

Технически я не вижу проблемы с вашим кодом.

Однако немного беспокоит то, что вы даже не начали работать над классом, который хотите протестировать, и у вас уже есть 4 макета, и «может быть гораздо больше». Это звучит как ужасно много настроек.

Кроме того, если я правильно понимаю [TestInitialize], это означает, что для каждого теста в этом классе каждый репозиторий будет настроен одинаково. Это, вероятно, будет мешать указанию тестов с разными условиями.

Возможно, вам следует подумать о том, чтобы избежать [TestInitialize] и настроить нужные вам репозитории в каждом методе тестирования, специфичные для того, что вы хотите утверждать, и постепенно извлекать настройки для каждого репозитория в общие методы, следуя стилю BDD: «Given_User_Of_Type_VIP()» возвращает репозиторий с пользователем типа VIPнастройка.

Комментарии:

1. Ну, причина, по которой я мог бы получить гораздо больше, заключается в том, что это класс обслуживания WCF, который реализует несколько servicecontracts, и в настоящее время я не использую TDD. У сервиса есть только класс RepositoryFactory, но я должен издеваться над репозиториями, которые он может вернуть.