FakeItEasy configure fake to throw exception and return value on the next call
Asked Answered
D

2

8

We have to implement a retry-mechanism.

To test the RetryProvider, I want a fake of a class to throw exceptions on the first two calls, but return a valid object on the third call.

Under normal circumstances (without throwing exceptions) we could use A.CallTo(() => this.fakeRepo.Get(1)).ReturnsNextFromSequence("a", "b", "c");

I want something similar:

  • First Call: throw new Exception();
  • Second Call: throw new Exception();
  • Third Call: return "success";

How can I configure my fake to do this?

Thanks in advance

Delicacy answered 30/10, 2017 at 14:3 Comment(0)
C
11
var fakeRepo = A.Fake<IFakeRepo>();

A.CallTo(() => fakeRepo.Get(1))
     .Throws<NullReferenceException>()
     .Once()
     .Then
     .Throws<NullReferenceException>()
     .Once()
     .Then
     .Returns('a');

See more about this at Specifying different behaviors for successive calls.

Canfield answered 30/10, 2017 at 14:29 Comment(0)
S
7

This should work:

A.CallTo(() => this.fakeRepo.Get(1))
    .Throws<Exception>().Twice()
    .Then
    .Returns("a");

Another way do it like the sequence:

var funcs = new Queue<Func<string>>(new Func<string>[]
{
    () => throw new Exception(),
    () => throw new Exception(),
    () => "a",
});
A.CallTo(() => this.fakeRepo.Get(1)).ReturnsLazily(() => funcs.Dequeue().Invoke()).NumberOfTimes(queue.Count);

Could have extension method:

public static IThenConfiguration<IReturnValueConfiguration<T>> ReturnsNextLazilyFromSequence<T>(
    this IReturnValueConfiguration<T> configuration, params Func<T>[] valueProducers)
{
    if (configuration == null) throw new ArgumentNullException(nameof(configuration));
    if (valueProducers == null) throw new ArgumentNullException(nameof(valueProducers));

    var queue = new Queue<Func<T>>(valueProducers);
    return configuration.ReturnsLazily(x => queue.Dequeue().Invoke()).NumberOfTimes(queue.Count);
}

An call it like this:

A.CallTo(() => this.fakeRepo.Get(1)).ReturnsNextLazilyFromSequence(
    () => throw new Exception(),
    () => throw new Exception(),
    () => "a");
Scarbrough answered 30/10, 2017 at 14:33 Comment(1)
Or Throws<Exception>().Twice().Then.Returns("a") ;)Fustigate

© 2022 - 2024 — McMap. All rights reserved.