如何在 Moq 的 SetUpSequence 上使用回调?
How to use Callback on Moq's SetUpSequence?
我使用的是 Moq 4.8 版,并且有一种方法可以模拟和断言其参数。我从这个模拟方法开始:
mock.Setup(m => m.Update(It.IsAny<MyClass>))
.Callback((MyClass c) =>
{
// some assertions
})
.Returns(Task.FromResult(updatedClass));
我在其中更新类型为 MyClass
的对象并对该对象执行大量断言。这很好用。
我刚刚向调用 Update
的方法添加了逻辑,以便在抛出异常时重试调用它。所以我想实现一个新的单元测试,抛出几次异常然后 returns 并且能够像以前一样进行断言。所以我尝试了 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
。有没有办法在保持预调用 Callback
到 Returns
的同时按顺序模拟 Throws
和 Returns
调用?
目前我一直在做这个作为变通方法:
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,但符合我的要求。
可以使用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);
我已经使用这种方法来捕获对方法的请求的每个实例以及 return 值序列。
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);
}
给定一些预定义的响应列表,以上将捕获对模拟方法发出的所有请求和return响应序列。
我使用的是 Moq 4.8 版,并且有一种方法可以模拟和断言其参数。我从这个模拟方法开始:
mock.Setup(m => m.Update(It.IsAny<MyClass>))
.Callback((MyClass c) =>
{
// some assertions
})
.Returns(Task.FromResult(updatedClass));
我在其中更新类型为 MyClass
的对象并对该对象执行大量断言。这很好用。
我刚刚向调用 Update
的方法添加了逻辑,以便在抛出异常时重试调用它。所以我想实现一个新的单元测试,抛出几次异常然后 returns 并且能够像以前一样进行断言。所以我尝试了 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
。有没有办法在保持预调用 Callback
到 Returns
的同时按顺序模拟 Throws
和 Returns
调用?
目前我一直在做这个作为变通方法:
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,但符合我的要求。
可以使用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);
我已经使用这种方法来捕获对方法的请求的每个实例以及 return 值序列。
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);
}
给定一些预定义的响应列表,以上将捕获对模拟方法发出的所有请求和return响应序列。