Search code examples
c#nsubstitute

NSubstitute multiple return sequence


I want to substitute object to return sequence of different objects. For example:

var http = Substitute.For<IHttp>();
http.GetResponse(Arg.Any<string>()).Returns(resourceString, resourceString2);
http.GetResponse(Arg.Any<string>()).Returns(x => { throw new Exception(); });

will return resourceString then resourceString2 then exception.

Or something like this:

var http = Substitute.For<IHttp>();
http.GetResponse(Arg.Any<string>()).Returns(resourceString, x => { throw new Exception(); }, resourceString2);

will return resourceString then exception then resourceString2.

How can I do that?


Solution

  • This answer is outdated — NSubstitute has direct support for this now. Please see @dangerdex's answer to this question for more information.


    The multiple returns syntax in NSubstitute only supports values. To also throw exceptions you'll need to pass a function to Returns, and implement the required logic yourself (e.g. Returns(x => NextValue())).

    There is a related example for Moq sequences on Haacked's blog using a queue. You can do a similar thing with NSubstitute (example code only, use at your own risk :)):

    public interface IFoo { int Bar(); }
    
    [Test]
    public void Example() {
        var results = new Results<int>(1)
                        .Then(2)
                        .Then(3)
                        .Then(() => { throw new Exception("oops"); });
        var sub = Substitute.For<IFoo>();
        sub.Bar().Returns(x => results.Next());
    
        Assert.AreEqual(1, sub.Bar());
        Assert.AreEqual(2, sub.Bar());
        Assert.AreEqual(3, sub.Bar());
        Assert.Throws<Exception>(() => sub.Bar());
    }
    
    public class Results<T> {
        private readonly Queue<Func<T>> values = new Queue<Func<T>>();
        public Results(T result) { values.Enqueue(() => result); }
        public Results<T> Then(T value) { return Then(() => value); }
        public Results<T> Then(Func<T> value) {
            values.Enqueue(value);
            return this;
        }
        public T Next() { return values.Dequeue()(); }
    }
    

    Hope this helps.