我正在尝试模拟 Visual Studio CommandBars实例。 CommandBars 实现非通用 IEnumerable 接口(interface)。为了能够迭代模拟,我设置了 GetEnumerable()。奇怪的是,只有当我将mock.Object作为CommandBars的实例访问时,这才有效。如果我将 is 转换为 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
最佳答案
通过检查实际类型
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
接口(interface)
您可以显式更改设置:
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 实现了这两个接口(interface),并为这两个接口(interface)独立定义了 GetEnumerator
。
关于c# - 将目标强制转换为 IEnumerable 时,莫清 GetEnumerable 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23885665/