我是一个界面,它有:
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 :(得分:7)
我建议反对它的原因有很多。首先,正如评论中所提到的,没有理由说真正的字典在这里不起作用。 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>
{@ 1}},因为@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);
为什么需要虚拟化?
Moq和其他类似的模拟框架只能模拟接口, 抽象方法/属性(在抽象类上)或虚拟 具体类的方法/属性。
这是因为它生成了一个将实现该接口的代理 或者创建一个派生类来覆盖那些可重写的方法 为了拦截电话。
<子> Credit to @aqwert 子>