2016-06-12 2 views
0

Я moqing интерфейс, который имеет:Неверная установка на не виртуального члена с использованием MOQ

Dictionary<string, object> InstanceVariables { get; set; }

Я создал новый макет интерфейса и пытается настроить его так, он возвращает только случайная строка так:

_mockContext.SetupGet(m => m.InstanceVariables[It.IsAny<string>()]).Returns(@"c:\users\randomplace");

Но я, кажется, получаю сообщение об ошибке:

{"Invalid setup on a non-virtual (overridable in VB) member: m => m.InstanceVariables[It.IsAny<String>()]"}

Что это значит? Я издеваюсь над интерфейсом, поэтому это не должно быть проблемой?

Благодаря

+0

Зачем вам нужно издеваться над «Словарем», если вы можете создать словарь для всех необходимых полей? – Valentin

+0

Поскольку я хочу изменить то, что появляется в экземпляре InstanceVariables, когда я выполняю метод, который я передал в моем объекте mockContext, в –

+3

. Ваша собственность - это словарь, а не 'IDictionary'. Поэтому, чтобы скомпилировать его, вы должны высмеивать конкретную реализацию, * не * интерфейс, как вы заявляете (хотя я точно не знаю, как вы не отправляли этот код). Следовательно, ошибка правильная - вы не можете переопределить не виртуальный член (а индексный словарь не является виртуальным).Тем не менее, вопрос @ Valentin все еще стоит - почему бы просто не создать словарь со значениями, установленными по вашему желанию для вашего модульного теста, - словарь - это немой магазин данных - там нет функциональности, чтобы издеваться! –

ответ

4

Там есть ряд причин, почему я советовал бы против него. Во-первых, как упоминалось в комментариях, нет причин, по которым настоящий словарь не будет работать здесь. We shouldn't mock types that what we don't own и only mock types we do own.
Линия _mockContext.SetupGet(m => m.InstanceVariables[It.IsAny<string>()]).Returns(@"c:\users\randomplace"); пытается высмеять Get на Dictionary<T, T>, который как примечания @RB не virtual, следовательно, ваша ошибка. Возможно, вы насмехаетесь над своим интерфейсом, но настроенный там на .NET.

Во-вторых, IMO, It.IsAny<string>() приводит к довольно слабым испытаниям, потому что он будет отвечать на любые строки. Структурирование что-то вроде:

const string MyKey = "someKey"; 

var dictionary = new Dictionary<string, object>(); 
dictionary.Add(MyKey, @"c:\users\randomplace"); 
_mockContext.Setup(m => m.InstanceVariables).Returns(dictionary); 

var sut = new SomeObject(_mockContext.Object()); 
var result = sut.Act(MyKey); 

// Verify 

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


Тем не менее, если вы абсолютно необходимо издеваться словарь, по причинам, которые не видны на вопрос ... то свойство на вашем интерфейсе должен быть интерфейс для словаря, IDictionary, не класс бетона:

IDictionary<string, object> InstanceVariables { get; set; } 

Тогда вы можете создать словарь макет с помощью:

var dictionary = new Mock<IDictionary<string, object>>(); 
dictionary.SetupGet(d => d[It.IsAny<string>()]).Returns(@"c:\users\randomplace"); 

Затем в контекстном издеваться:

_mockContext.SetupGet(d => d.InstanceVariables).Returns(dictionary.Object); 

Почему нужно быть Virtual?

Moq and other similar mocking frameworks can only mock interfaces, abstract methods/properties (on abstract classes) or virtual methods/properties on concrete classes.

This is because it generates a proxy that will implement the interface or create a derived class that overrides those overrideable methods in order to intercept calls.
Credit to @aqwert

+0

Хороший ответ. Чтобы убедиться в том, что указатель конкретного класса 'Dictionary <,>' действительно не виртуальный, см. [Его документация] (https://msdn.microsoft.com/en-us/library/9tee9ht2.aspx). Чтобы увидеть, что интерфейс 'IDictionary <,>' включает член (индекс), см. [Его страница] (https://msdn.microsoft.com/en-us/library/zyxt2e2h.aspx). Я абсолютно согласен с тем, что, вероятно, лучше всего создать стандартный заполненный «Словарь <,>» в тесте и вернуть его из макета. Однако во втором подходе вам не нужно настраивать 'It.IsAny ()'. Вы можете настроить только 'd => d [" someKey "]', если хотите. –

Смежные вопросы