【问题标题】:Mocking GetEnumerator using Moq使用 Moq 模拟 GetEnumerator
【发布时间】:2017-05-26 04:14:00
【问题描述】:

我正在尝试在 Microsoft.Office.Interop.Word 程序集中模拟 Variables 界面

var variables = new Mock<Variables>();
variables.Setup(x => x.Count).Returns(2);
variables.Setup(x => x.GetEnumerator()).Returns(TagCollection);

private IEnumerator TagCollection()
{
    var tag1 = new Mock<Variable>();
    tag1.Setup(x => x.Name).Returns("Foo");
    tag1.Setup(x => x.Value).Returns("Bar");

    var tag2 = new Mock<Variable>();
    tag2.Setup(x => x.Name).Returns("Baz");
    tag2.Setup(x => x.Value).Returns("Qux");

    yield return tag1.Object;
    yield return tag2.Object;
}

我的代码如下所示:

// _variables is an instance of Variables interface
var tags = from variable in _variables.OfType<Variable>()
           where variable.Name == "Foo"
           select variable.Value;
var result = tags.ToList();

上面代码的最后一行抛出了 NullReferenceException。如果我使用 foreach 循环遍历 _variables 集合,我可以毫无问题地访问 Variable 的模拟对象。我在这里做错了什么?

【问题讨论】:

  • 您的foreach 的工作原理是什么样的?
  • 对不起,这是一个疯狂的猜测,但我在模拟期间返回迭代集合时遇到了类似的问题,这是因为我没有在最后调用列表。试试这个:var tags = variables.OfType&lt;Variable&gt;().Where(x =&gt; x.Name == "Foo").Select(x =&gt; x.Value).ToList();
  • @William OP 在下一行调用 ToList
  • @William 它抛出 NullReferenceException
  • 我的猜测是OfType 对模拟对象不太好。您是否将OfType 与有效的foreach 一起使用?还有什么类型的_variables 需要你首先使用OfType

标签: c# moq


【解决方案1】:

试试:

variables
    .As<IEnumerable>()
    .Setup(x => x.GetEnumerator()).Returns(TagCollection);

有两种不同的方法,一种在基接口中声明,另一种在Variables 中声明。

当您直接foreach 时,会调用后者,因为该方法隐藏基类型中外观相同的成员。 foreach 在存在时调用 public 方法,在这种情况下 IEnumerable 无关紧要。

当您调用.OfType&lt;Variable&gt;() Linq 扩展时,引用被强制转换为IEnumerable 接口,名称隐藏不再存在。基接口上的方法被调用。

这就像以下之间的区别:

_variables.GetEnumerator();

和:

((IEnumerable)_variables).GetEnumerator();

您可以认为 Moq 生成的模拟量是这样的:

public class TheTypeMoqMakes : Variables 
{
  Enumerator Variables.GetEnumerator()
  {
    // Use return value from after
    // expression tree you provided with 'Setup' without 'As'.
    // If you did not provide one, just return null.
  }

  Enumerator IEnumerable.GetEnumerator()
  {
    // Use return value from after
    // expression tree you provided with 'Setup' with 'As<IEnumerable>'.
    // If you did not provide one, just return null.
  }

  // other methods and properties
}

如果成员不是Setup,Moq 返回 null 的原因是你有MockBehavior.Loose。请始终考虑使用MockBehavior.Strict


我不明白为什么Variables接口chose to use method hiding的作者在这种情况下。

【讨论】:

  • 谢谢你,成功了。因为 设置对我来说是全新的。
猜你喜欢
  • 2011-10-05
  • 2011-06-13
  • 2019-09-11
  • 2010-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多