我试图嘲笑Visual Studio CommandBars个实例。 CommandBars实现非通用的IEnumerable接口。为了能够迭代模拟,我设置了GetEnumerable()。奇怪的是,这只有在我将mock.Object作为CommandBars的一个实例访问时才有效。如果我转换为IEnumerable(因为它在使用Linq方法时隐式发生),GetEnumerable()突然返回null。有人可以解释这种行为吗?
var mockCommandBars = new Mock<CommandBars>();
IEnumerable bars = new List<CommandBar>();
mockCommandBars.Setup(cb => cb.GetEnumerator()).Returns(bars.GetEnumerator);
var cbs = mockCommandBars.Object;
var cbs1 = cbs.GetEnumerator(); // returns instance
var ecbs = (IEnumerable) cbs;
var cbs2 = ecbs.GetEnumerator(); // returns null!
编辑:我使用的是Moq 4.2.1402.2112
答案 0 :(得分:6)
通过检查
的实际类型 var cbs = mockCommandBars.Object;
在运行时,似乎cbs已被包装为:
cbs {Castle.Proxies.CommandBarsProxy}
而IEnumerable
的演员表会干扰代理人的行为。
您可以使用此post here中的帮助方法来连接代理的__target
属性,例如
var cbs2 = UnwrapProxy<IEnumerator>(cbs.GetEnumerator());
,其中
internal static TType UnwrapProxy<TType>(TType proxy)
{
try
{
dynamic dynamicProxy = proxy;
return dynamicProxy.__target;
}
catch (RuntimeBinderException)
{
return proxy;
}
}
修改强>
From Here很明显,设置未在基础_CommandBars.IEnumerable
界面上执行
您可以明确更改设置:
var cbs = mockCommandBars.As<_CommandBars>().As<IEnumerable>();
cbs.Setup(cb => cb.GetEnumerator()).Returns(bars.GetEnumerator());
var ecbs = (IEnumerable)cbs.Object; // The cast is now redundant.
var cbs2 = ecbs.GetEnumerator();
如果你想保留一个模拟变量来传递,你可以像这样设置它。
var mockCommandBars = new Mock<CommandBars>();
mockCommandBars.Setup(cb => cb.GetEnumerator()).Returns(bars.GetEnumerator);
mockCommandBars.As<IEnumerable>().Setup(cb => cb.GetEnumerator()).Returns(bars.GetEnumerator);
这告诉Moq Mock实现了两个接口,并为两者独立定义GetEnumerator
。