【问题标题】:How to mock IDataRecord?如何模拟 IDataRecord?
【发布时间】:2013-05-08 08:04:45
【问题描述】:

我正在尝试使用 Moq 模拟 IDataRecord

模拟创建如下:

Mock<IDataRecord> mockDataRecord = new Mock<IDataRecord>();

被测行是:

DateTime timestamp = dataRecord.GetValueOrDefault<DateTime>("QUEUE_ADD_TS");

试过了:

mockDataRecord.Setup(r => r.GetValueOrDefault<DateTime>("QUEUE_ADD_TS")).Returns(now);

...但它给出了运行时错误:

表达式引用了一个不属于被模拟的方法 对象:r => r.GetValueOrDefault("QUEUE_ADD_TS")

还尝试用It.IsAny&lt;String&gt;() 代替"QUEUE_ADD_TS",但没有任何区别。这应该很容易,但我摸不着头脑 - 感谢任何建议!

【问题讨论】:

  • 我在IDataRecord 接口上看不到GetValueOrDefault&lt;T&gt; 方法。不是扩展方法吗?
  • 很确定它就像错误所暗示的那样。 GetValueOrDefault 是一种扩展方法,因此不能直接存根。尝试对索引器进行存根,我相信示例会在某处:)
  • 啊,你们都对!原来GetValueOrDefault 是一个扩展方法并且是static 所以可能不容易被嘲笑。不太清楚这是如何工作的,但正在研究它......

标签: c# unit-testing mocking moq


【解决方案1】:

我这样做,又快又脏:

Mock<IDataRecord> dataRecord = new Mock<IDataRecord>();
dataRecord.Setup(column => column["applicationno"]).Returns("foobar");
dataRecord.Setup(column => column["numberOfApplications"]).Returns(12);

【讨论】:

    【解决方案2】:

    您不能模拟静态或扩展方法,因为大多数模拟框架在后台使用动态代理。

    在您的测试中,不要存根扩展方法。相反,将原始方法本身存根,例如:

    mockDataRecord.Setup(r => r.GetValue<DateTime>("QUEUE_ADD_TS")).Returns(now);
    

    您应该单独测试扩展方法,例如:

    1. 存根 GetValue 方法并断言 GetValueOrDefault 返回存根值。

    2. 不要存根 GetValue 方法,并断言 GetValueOrDefault 返回默认值。

    【讨论】:

    • 这确实是我现在正在做的——之前实际上没有遇到过扩展方法! (我不知道,你离开 c# 几年回来了,球门柱已经移动了;-))。我唯一的问题是有 lot 的 Setup 方法,而关于 StackOverflow 的普遍共识是每个 Setup() 都应与等效的 Verify() 匹配。似乎有点矫枉过正,并且会使代码更难维护 - 我真的需要这样做还是可以用 Verifiable() 代替?
    • VerifyAll() 似乎比将每个 Setup() 与 Verify() 配对更好。显然,这应该根据具体情况进行。你会是最好的评判者:-)
    • 我已经完成了上面所说的,是这样的:this.dataRecord.Setup(d => d.GetValue("WorkItemId")).Returns(1);但我得到对象引用未设置为对象的实例....我做错了什么?看来我和评论里的一样。
    • 好吧,对不起,我知道我做错了什么。我在 setuptests 方法中声明了新的 Mock 。而且这个方法没有注释TestInitialize。所以该对象从未被创建...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-26
    • 1970-01-01
    • 1970-01-01
    • 2012-08-03
    • 2014-07-01
    • 1970-01-01
    相关资源
    最近更新 更多