NSubstitute multiple return sequence

孤者浪人 提交于 2020-07-18 11:36:55

问题


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?


回答1:


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.




回答2:


This is now a supported feature in NSubstitute with a very friendly interface.

It would be something like...

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

Documentation can be found here




回答3:


Here's an example that does everything inline without an extra class. If you were doing this a lot I would probably go with the separate class option.

[Test]
public void WhenSomethingHappens()
{
    var something = Substitute.For<ISomething>();
    int callCount = 0;
    something.SomeCall().Returns(1, 2);
    something.When(x => x.SomeCall()).Do(obj => { if (++callCount == 3) throw new Exception("Problem!"); });

    Assert.AreEqual(1, something.SomeCall());
    Assert.AreEqual(2, something.SomeCall());
    Assert.Throws<Exception>(() => something.SomeCall());
}


public interface ISomething
{
    int SomeCall();
}



回答4:


Another example with out parameter. Moreover it is usueful for some scenarios when function is called periodically in separated thread. We can simulate/mock each call differently.

   List<AnyClass> items = new List<AnyClass>();

   mockIService.TryDoSth(out response).ReturnsForAnyArgs(p =>
            {
                p[0] = items;
                return true;
            }, 
            p =>
            {
                p[0] = items;
                return true;
            }, p =>
            {
                throw new Exception("Problem!"); 
            });

bool TryDoSth(out List result);



来源:https://stackoverflow.com/questions/12163840/nsubstitute-multiple-return-sequence

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!