#c# #unit-testing #generics #moq #unity-container
#c# #модульное тестирование #дженерики #moq #unity-контейнер
Вопрос:
У меня есть интерфейс контейнера с универсальным методом разрешения, который при реализации разрешается с использованием Unity.
public interface IContainer
{
T Resolve<T>();
}
В настоящее время существует макет класса контейнера:
public class MockContainer : IContainer {
public T Resolve<T>()
{
return default(T);
}
}
Но я хочу использовать Moq для согласованности и сделать эквивалентный:
mockContainer
.Setup(container => container.Resolve<T>())
.Returns(default(T));
Но я получаю 2 ошибки компиляции 'T' could not be found
Является ли синтаксис Moq неправильным, я пропускаю ссылку или это просто невозможно сделать?
Редактировать Я знаю, что издевательство над контейнером не идеально. Я мог бы разрешить каждый класс один за другим в своем коде настройки.
Мой вопрос заключается в том, существует ли какой-либо синтаксис Moq для выполнения эквивалента моего фактического контейнера.
Комментарии:
1. Я думаю, справедливый вопрос: зачем вам все равно нужно издеваться над разрешением, разве вы не используете внедрение зависимостей?
Ответ №1:
Обычно вы не можете этого сделать (настроить общие методы без указания типа), но если вы хотите только return default(T)
и вам все равно, вызывается ли функция вообще, достаточно просто создать макет без вызова Setup
:
var mockZincContainer = new Mock<IContainer>();
// works just fine
mockZincContainer.Object.Resolve<DateTime>(); // returns default(DateTime)
mockZincContainer.Object.Resolve<object>(); // returns default(object)
Вы даже можете возвращать макеты вместо default(T)
этого, изменяя DefaultValue
свойство макета с DefaultValue.Empty
на DefaultValue.Mock
.
Ответ №2:
Вам не нужно извлекать макет объекта из вашего интерфейса. Так что избавьтесь от MockContainer.
На этом этапе в вашем модульном тестировании вы должны знать, какие типы вы хотите протестировать. Итак, на этом этапе просто дайте ему реальный тип и скажите, что возвращать.
т.е.
//arrange
mockZincContainer
.Setup(container => container.Resolve<ISomeInterface>())
.Returns(new ConcreteClassThatDerivesFromSomeInterface());
var testClass = new ClassToBeTested(mockZincContainer.Object);
//act
testClass.DoYourMethod();
//assert
mockZincContainer.Verify(c => c.Resolve<ISomeInterface>(), Times.Once);
Комментарии:
1. к сожалению, эти модульные тесты являются интеграционными тестами, и запись этих настроек и возвратов для каждой используемой зависимости требует времени и подвержена ошибкам.
Ответ №3:
Зачем вам издеваться над контейнером? Это скорее проблема интеграции. Весь ваш код должен быть тестируемым без подключения к контейнеру. Издевательство над контейнером для возврата зависимости, которую вы затем передаете потребляющим классам, кажется мне большой тратой времени.
Комментарии:
1. В идеале да. На самом деле модульные тесты — это интеграционные тесты, и у меня нет свободы переписывать ~ 50 000 модульных тестов