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

Moqing getenenumerable在将target转换为IEnumerable时失败

通过检查

的实际类型
 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