将目标转换为IEnumerable时,Moqing GetEnumerable失败

时间:2014-05-27 09:23:34

标签: c# moq ienumerable

我试图嘲笑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

1 个答案:

答案 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