Reputation: 2144
I'm using Moq version 4.8 and have a method to mock and assert its parameter. I started with this mocked method:
mock.Setup(m => m.Update(It.IsAny<MyClass>))
.Callback((MyClass c) =>
{
// some assertions
})
.Returns(Task.FromResult(updatedClass));
where I update an object of type MyClass
and do a number of assertions on that object. This works just fine.
I've just added logic to the method calling Update
to retry calling it if exceptions are thrown. So I want to implement a new unit test that throws exceptions a few times and then returns and be able to do the assertions like before. So I tried SetupSequence
as follows:
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));
But ISetupSequence
doesn't support Callback
. Is there a way to mock Throws
and Returns
calls in order while keeping a pre call Callback
to Returns
?
Upvotes: 12
Views: 11903
Reputation: 639
I have used this approach to capture each instance of a request to a method and also return a sequence of values.
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);
}
Given some list of pre-defined responses, the above will capture all the requests made to a mocked method and return the sequence of responses.
Upvotes: 6
Reputation: 249
You can use MockSequence, so that you can add Callback after .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);
Upvotes: 9
Reputation: 2144
For the time being I've been doing the this as a work around:
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));
Feels like a hack, but does what I'm looking for.
Upvotes: 5