【问题标题】:How to use Callback on Moq's SetUpSequence?如何在 Moq 的 SetUpSequence 上使用回调?
【发布时间】:2020-11-26 23:59:24
【问题描述】:

我使用的是 Moq 4.8 版,并且有一个模拟和断言其参数的方法。我从这个模拟方法开始:

mock.Setup(m => m.Update(It.IsAny<MyClass>))
    .Callback((MyClass c) =>
    {
        // some assertions
    })
    .Returns(Task.FromResult(updatedClass));

我更新MyClass 类型的对象并对该对象执行许多断言。这工作得很好。

我刚刚为调用Update 的方法添加了逻辑,以便在抛出异常时重试调用它。所以我想实现一个新的单元测试,它会抛出几次异常然后返回并能够像以前一样进行断言。于是我试了SetupSequence如下:

mock.SetupSequence(m => m.Update(It.IsAny<MyClass>))
    .Throws(new Exception("test exception 1"))
    .Throws(new Exception("test exception 2"))
    .Callback((MyClass c) =>
    {
        // some assertions
    })
    .Returns(Task.FromResult(updatedClass));

但是ISetupSequence 不支持Callback。有没有办法按顺序模拟ThrowsReturns 调用,同时保持CallbackReturns 的预调用?

【问题讨论】:

  • 您可以查看 Moq 存储库中的 #573 问题。以及Moq sequential callbacks。不确定它是否更优雅,因为它是基于意见的
  • 感谢您的链接,它们很有帮助。还改写了问题,以减少基于意见的问题。我的工作对我来说就像是一个黑客,这就是为什么我正在寻找一种更好的方法来做这件事。
  • 你检查过this吗?

标签: c# mocking moq


【解决方案1】:

你可以使用MockSequence,这样你就可以在.Setup()之后添加Callback。

var mock = new Mock<IFoo>(MockBehavior.Strict);
var sequence = new MockSequence();

_fooService.InSequence(sequence).Setup(x => x.FooMethod(a)).ReturnsAsync(b);
_barService.InSequence(sequence).Setup(x => x.BarMethod(c)).ReturnsAsync(d);
_bazService.InSequence(sequence).Setup(x => x.BazMethod(e)).ReturnsAsync(f);

【讨论】:

  • 虽然你可以在InSequence 上调用.Setup,但你不能调用.Throw.Callback,这正是我要找的。​​span>
  • @alamoot - 回调仅在设置后有效。这是解决方案,非常适合我:-)
  • 效果很好,谢谢。
【解决方案2】:

暂时我一直在做这个作为解决方法:

int callCount = 0;
mock.Setup(m => m.Update(It.IsAny<MyClass>))
    .Callback((MyClass c) =>
    {
        callCount++;
        if (callCount <=2)
        {
            throw new Exception($"Test Exception #{callCount}");
        }
        else
        {
            callCount = 0; // this is needed if you're gonna use callCount for multiple setups
            // some assertions
        }
    })
    .Returns(Task.FromResult(updatedClass));

感觉像一个 hack,但做了我想要的。

【讨论】:

    【解决方案3】:

    我已经使用这种方法来捕获对方法的请求的每个实例,并返回一系列值。

    var requests = new List<SomeRequest>();
    var sequence = new MockSequence();
    foreach (var response in responses)
    {
        someMock.InSequence(sequence)
            .Setup(x => x.SomeMethod(It.IsAny<SomeRequest>()))
            .Callback<SomeRequest>(r => requests.Add(r))
            .ReturnsAsync(response);
    }
    

    给定一些预定义的响应列表,上面将捕获对模拟方法发出的所有请求并返回响应序列。

    【讨论】:

      猜你喜欢
      • 2017-02-04
      • 2019-09-09
      • 2023-04-01
      • 2015-11-19
      • 1970-01-01
      • 2020-02-08
      • 2022-09-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多