mag*_*_nz 1 c# testing unit-testing 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>()]"}
这究竟是什么意思?我在嘲笑界面所以不应该这不是问题吗?
谢谢
我建议反对它的原因有很多.首先,正如评论中所提到的,没有理由说真正的字典在这里不起作用.我们应该什么我们不拥有不模拟类型和唯一的模拟类型的我们自己.
该行_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
Run Code Online (Sandbox Code Playgroud)
因为如果正确的密钥是由您的被测系统(sut)给出/或生成的,字典只能响应路径,将会更强大.
也就是说,如果你绝对必须模拟一个字典,由于问题上不明显的原因......那么你的界面上的属性需要是字典的接口IDictionary,而不是具体的类:
IDictionary<string, object> InstanceVariables { get; set; }
Run Code Online (Sandbox Code Playgroud)
然后你可以通过以下方式创建字典模拟:
var dictionary = new Mock<IDictionary<string, object>>();
dictionary.SetupGet(d => d[It.IsAny<string>()]).Returns(@"c:\users\randomplace");
Run Code Online (Sandbox Code Playgroud)
然后在上下文模拟:
_mockContext.SetupGet(d => d.InstanceVariables).Returns(dictionary.Object);
Run Code Online (Sandbox Code Playgroud)
为什么需要虚拟化?
Moq和其他类似的模拟框架只能模拟接口,抽象方法/属性(在抽象类上)或具体类上的虚方法/属性.
这是因为它生成了一个代理,它将实现接口或创建一个派生类,该类覆盖那些可重写的方法以拦截调用.
感谢@aqwert