NSubstitute多个返回序列

12

我想要用另一组对象替换返回的对象序列。

例如:

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

将返回resourceString,然后是resourceString2,最后是exception。

或者类似于这样:

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

我该如何做到这一点?将返回resourceString,然后是异常,最后是resourceString2。


我已经向NSubstitute提交了一个pull request,以支持此功能。 - Alexandr Nikitin
4个回答

34

现在,在NSubstitute中支持了这个特性,并提供了非常友好的接口。

大概是这样的...

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

文档可以在这里找到


16

此答案已过时 - NSubstitute现在直接支持此功能。有关更多信息,请参见此问题的@dangerdex的答案


NSubstitute中的多个返回语法仅支持值。要抛出异常,您需要将函数传递给Returns并自己实现所需的逻辑(例如Returns(x => NextValue()))。

Haacked的博客上有一个相关的示例,使用队列展示了Moq序列。您可以使用类似的方法在NSubstitute中实现(仅限示例代码,请自行承担风险 :)):

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()(); }
}

希望这有所帮助。

3

这里有一个例子,它在没有额外类的情况下完成所有内联操作。如果您需要经常这样做,我建议使用单独的类选项。

[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();
}

谢谢,使用额外类的方式似乎更容易阅读和实现。 - Alexandr Nikitin

0

另一个带有无参数的例子。此外,当函数在分离的线程中被周期性地调用时,它对某些场景非常有用。我们可以模拟/模仿每个调用的不同情况。

   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);

尝试执行某项任务并返回一个布尔值,同时将结果存储在列表中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接