C# 使用MOQ在非虚拟成员上的设置无效
我是莫清,一个界面,它有:C# 使用MOQ在非虚拟成员上的设置无效,c#,unit-testing,testing,moq,C#,Unit Testing,Testing,Moq,我是莫清,一个界面,它有: 字典实例变量{get;set;} 我创建了一个新的接口模拟,并尝试将其设置为只返回一个随机字符串,如下所示: \u mockContext.SetupGet(m=>m.InstanceVariables[It.IsAny()])。返回(@“c:\users\randomplace”) 但我似乎犯了一个错误: {“非虚拟(在VB中可重写)成员上的设置无效:m=>m.InstanceVariables[It.IsAny()]”} 这到底是什么意思?我在模仿界面,所以这不是
字典实例变量{get;set;}
我创建了一个新的接口模拟,并尝试将其设置为只返回一个随机字符串,如下所示:
\u mockContext.SetupGet(m=>m.InstanceVariables[It.IsAny()])。返回(@“c:\users\randomplace”)代码>
但我似乎犯了一个错误:
{“非虚拟(在VB中可重写)成员上的设置无效:m=>m.InstanceVariables[It.IsAny()]”}
这到底是什么意思?我在模仿界面,所以这不是一个问题吗
谢谢我有很多理由反对它。首先,正如评论中提到的,没有理由认为真正的字典在这里不起作用。和
行\u mockContext.SetupGet(m=>m.InstanceVariables[It.IsAny()])。返回(@“c:\users\randomplace”)
试图模拟字典
上的获取
,而@RB notes不是虚拟的
,因此您的错误。您可能在模拟您的接口,但设置在.NET字典上
其次,IMO,It.IsAny()
会导致非常弱的测试,因为它会响应任何字符串。结构类似于:
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
然后,您可以通过以下方式创建字典模拟:
var dictionary = new Mock<IDictionary<string, object>>();
dictionary.SetupGet(d => d[It.IsAny<string>()]).Returns(@"c:\users\randomplace");
为什么它需要是虚拟的?
Moq和其他类似的模拟框架只能模拟接口,
抽象方法/属性(在抽象类上)或虚拟
具体类的方法/属性
这是因为它生成了一个将实现接口的代理
或者创建一个派生类,该派生类重写中的那些可重写方法
命令拦截呼叫。
我反对它有很多理由。首先,正如评论中提到的,没有理由认为真正的字典在这里不起作用。和
行\u mockContext.SetupGet(m=>m.InstanceVariables[It.IsAny()])。返回(@“c:\users\randomplace”)
试图模拟字典
上的获取
,而@RB notes不是虚拟的
,因此您的错误。您可能在模拟您的接口,但设置在.NET字典上
其次,IMO,It.IsAny()
会导致非常弱的测试,因为它会响应任何字符串。结构类似于:
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
然后,您可以通过以下方式创建字典模拟:
var dictionary = new Mock<IDictionary<string, object>>();
dictionary.SetupGet(d => d[It.IsAny<string>()]).Returns(@"c:\users\randomplace");
为什么它需要是虚拟的?
Moq和其他类似的模拟框架只能模拟接口,
抽象方法/属性(在抽象类上)或虚拟
具体类的方法/属性
这是因为它生成了一个将实现接口的代理
或者创建一个派生类,该派生类重写中的那些可重写方法
命令拦截呼叫。
如果可以创建一个字典,那么为什么需要模拟一个字典
呢?因为当我执行在mockContext对象中传递给属性的方法时,我想更改InstanceVariables产生的内容。您的属性是字典
,而不是IDictionary
。因此,要使其编译,您必须模拟具体的实现,而不是您所说的接口(尽管我不能确定,因为您没有发布该代码)。因此,错误是正确的-您不能覆盖非虚拟成员(并且字典索引器不是虚拟的)。然而,@Valentin的问题仍然存在——为什么不创建一个字典,其中的值按照您对单元测试的期望设置——字典是一个愚蠢的数据存储——这里没有可模仿的功能!如果可以创建一个字典,那么为什么需要模拟一个字典
呢?因为当我执行在mockContext对象中传递给属性的方法时,我想更改InstanceVariables产生的内容。您的属性是字典
,而不是IDictionary
。因此,要使其编译,您必须模拟具体的实现,而不是您所说的接口(尽管我不能确定,因为您没有发布该代码)。因此,错误是正确的-您不能覆盖非虚拟成员(并且字典索引器不是虚拟的)。然而,@Valentin的问题仍然存在——为什么不创建一个字典,其中的值按照您对单元测试的期望设置——字典是一个愚蠢的数据存储——这里没有可模仿的功能!回答得好。要查看具体类字典
的索引器确实是非虚拟的,请参阅。要查看接口IDictionary
是否包含成员(索引器),请参阅。我完全同意,最好在测试中创建一个标准的字典
,并从模拟中返回。但是,在第二种方法中,您不必设置It.IsAny()
。如果需要,您只能设置d=>d[“someKey”]
。回答得好。要查看具体类字典
的索引器确实是非虚拟的,请参阅。要查看接口IDictionary
是否包含成员(索引器),请参阅。我完全同意,最好在测试中创建一个标准的字典
,并从模拟中返回。但是,在第二种方法中,您不必设置It.IsAny()
。如果需要,您只能设置d=>d[“someKey”]
。