如何在 Moq 的 SetUpSequence 上使用回调?

ala*_*oot 11 c# moq mocking

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

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

我在其中更新类型的对象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));
Run Code Online (Sandbox Code Playgroud)

ISetupSequence不支持Callback。有没有办法在保持预调用的同时按顺序模拟Throws和调用?ReturnsCallbackReturns

小智 9

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

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);
Run Code Online (Sandbox Code Playgroud)


Ben*_*son 6

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

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);
}
Run Code Online (Sandbox Code Playgroud)

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


ala*_*oot 3

目前我一直在这样做作为一种解决方法:

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));
Run Code Online (Sandbox Code Playgroud)

感觉像是黑客,但确实是我想要的。