Логика повтора, имеющая модульные тесты, работает как положено. Теперь я пытаюсь протестировать код, использующий логику повтора.
Код: Выделить всё
public async Task ExecuteWithRetriesAsync(Func action, int maxRetryCount = 3, int delayInSeconds = 5)
{
var attempted = 0;
while (attempted < maxRetryCount)
{
try
{
await action();
return true;
}
catch (DataServiceClientException ex) when (ex.StatusCode == 429)
{
attempted++;
var randomRetryDelay = _delayProvider.Generate(delayInSeconds, 2);
await Task.Delay(TimeSpan.FromSeconds(randomRetryDelay));
delayInSeconds += 5;
}
}
return false;
}
Код: Выделить всё
public async Task TryDeleteAsync(ToDelete toDelete)
{
try
{
// some logic before we save
await _someClient.SaveChangesAsync();
}
catch (DataServiceClientException ex)
{
var deletedSuccessfully = await _retryHandler.ExecuteWithRetriesAsync(async () => await _someClient.SaveChangesAsync());
if (deletedSuccessfully)
{
return;
}
throw;
}
}
Код: Выделить всё
[Fact]
public async Task TryDeleteAsync_AllRetriesFail_ShouldThrow()
{
var something = MockDataCreator.CreateSomething();
var something2 = MockDataCreator.CreateSomething(something);
_retryHandlerMock
.Setup(x => x.ExecuteWithRetriesAsync(It.IsAny(), 3, 5))
.Callback(async (action, _, _) =>
{
await action();
})
.ReturnsAsync(false); // returns false because all retries failed
_someClientMock
.SetupSequence(x => x.SaveChangesAsync())
.Throws(new DataServiceClientException(429)) // First try fails
.Throws(new DataServiceClientException(429)) // Second try fails
.Throws(new DataServiceClientException(429)) // Third try fails
.Throws(new DataServiceClientException(429)); // Fourth try fails
await Assert.ThrowsAsync(
async () => await _sut.TryDeleteAsync(something2));
_someClientMock.Verify(x => x.SaveChangesAsync(), Times.Exactly(4)); // Assertion fails because it's only called twice
_retryHandlerMock.Verify(x => x.ExecuteWithRetriesAsync(It.IsAny(), 3, 5), Times.Once);
}
Подробнее здесь: https://stackoverflow.com/questions/788 ... d-with-moq