Moqing getenenumerable在将target转换为IEnumerable时失败
本文关键字:IEnumerable 失败 转换 getenenumerable 在将 target Moqing | 更新日期: 2023-09-27 18:05:24
我试图模拟Visual Studio命令栏实例。commandbar实现了非泛型IEnumerable接口。为了能够对模拟进行迭代,我设置了getenenumerable()。奇怪的是,这只有在我访问模拟时才有效。对象作为命令栏的实例。如果我将它强制转换为IEnumerable(就像使用Linq方法时隐式发生的那样),getenenumerable()突然返回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
会干扰代理的行为。
您可以使用这篇文章中的helper方法来连接代理的__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;
}
}
编辑
从这里开始,很明显设置没有在底层_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();
如果您想保留一个mock变量来传递,您可以这样设置它。
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
。