【问题标题】:Moq throws NullReferenceException exception when setup has a callback安装程序有回调时 Moq 抛出 NullReferenceException 异常
【发布时间】:2018-07-17 13:46:31
【问题描述】:

我有一个单元测试。当我为我的接口函数的设置定义回调函数并在调用 Moq 上调用验证时抛出 NullReferenceException 异常,我真的很困惑。

更新: 我忘了提到重要的部分。 当我一一运行测试时一切正常,但是当我运行所有测试时,此测试失败。

例外:

System.NullReferenceException : Object reference not set to an instance of an object.
   at Moq.MethodCall.Matches(ICallContext call)
   at System.Linq.Enumerable.WhereListIterator`1.MoveNext()
   at System.Linq.Enumerable.Count[TSource](IEnumerable`1 source)
   at Moq.Mock.VerifyCalls(Interceptor targetInterceptor, MethodCall expected, Expression expression, Times times)
   at Moq.Mock.Verify[T](Mock mock, Expression`1 expression, Times times, String failMessage)
   at Moq.Mock`1.Verify(Expression`1 expression, Times times)
   at LimitTest.LimitEditor.LimitEditorTest.EditActionSetExistingLimit(Boolean add) in

单元测试:

var io= new Mock<ILimitServiceIO>(MockBehavior.Strict);
var LimitServiceIO= new MemoryLimitServiceIO();

... different setups...

io.Setup(x => x.PersistActionSet(It.Is<string>(id=>id==companyId), It.IsAny<IList<CsiNotificationActionSet>>()))
                .Callback((string compid, IList<CsiNotificationActionSet> sets) =>LimitServiceIO.PersistActionSet(compid, sets));

... Do some actions...

//This line throws exception
mockIo.Verify(x => x.PersistActionSet(measure.CompanyId,
            It.IsAny<IList<CsiNotificationActionSet>>()), Times.Once());

Assert.AreEqual(2,LimitServiceIO.ActionSets.First(acs => acs.Id == ACTION_SET_A1).Actions.Count,
                "Number of Actions does not match");

PersistActionSet方法的签名是:

void PersistActionSet(string companyId, IList<CsiNotificationActionSet> actionSets)

非常感谢它发生的任何想法或指针。

【问题讨论】:

  • 您能否向我们展示您要覆盖的原始PersistActionSet 的签名?
  • 另外,你似乎在Callback之前缺少.Verifiable()
  • @zaitsman 这是签名:void PersistActionSet(string companyId, IList actionSets);没有真正覆盖任何只是实现
  • @zaitsman 为什么需要回调之前的 .Verifiable()?
  • @OldFox Moq 版本是 4.8.2,我使用 mockIo 来验证调用。 LimitServiceIO 具有硬编码的对象,实际上将被检索。完整的代码是很多代码,所以尽量给出最重要的。为什么严格的模拟是一种不好的做法,任何关于更好做法的指针/文章?

标签: c# unit-testing mocking moq assert


【解决方案1】:

也为后人发帖,因为我现在也遇到过几次这个问题,谷歌的结果都没有为我解决这个问题。

如果我们有一个带有方法public string Foo(string s) 的类的模拟对象,并且我们想对传递给该方法的参数做一些事情,我发现的所有结果都表明您需要使用这样的回调:

mockObject.Setup(m => m.Foo(It.IsAny<string>()))
    .Callback<string>((s) => { /* Do something with parameter s */ });

但这会产生 NullReferenceException。对我来说解决问题的是在Callback() 之前添加一个Returns() Callback()

mockObject.Setup(m => m.Foo(It.IsAny<string>()))
    .Returns("bar")
    .Callback<string>((s) => { /* Do something with parameter s */ });

【讨论】:

    【解决方案2】:

    为了后代和其他人突然遇到奇怪的错误。 在测试中设置 STAThread 属性解决了这个问题

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-11
      • 2013-04-09
      • 2017-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-11
      • 2013-05-23
      相关资源
      最近更新 更多