c# - 如何在单元测试执行中更改方法的返回值

标签 c# unit-testing xunit.net nsubstitute

我正在尝试设计一个单元测试来测试重试循环模式。我能想到的唯一方法是在测试进行到一半时更改嵌入在重试循环核心的方法返回的内容。

例如...我想在测试的前 5 秒内为特定方法抛出异常。然后停止抛出该异常,并在该点之后实际响应一些有效数据。

前 5 秒:

service.MethodToRetry(Arg.Any<string>()).ThrowsForAnyArgs(new Exception());

然后异常条件被移除并且 MethodToRetry() 正常完成。

这是可能的还是我的做法完全错误?我在 c# 中使用 xunit 和 nsubstitute 工作。

最佳答案

注意:这里的测试是为了演示 NSubstitute 的行为。在实际测试中,我们不会测试替代品。 :)

测试重试的一种方法是 stub 多次返回(如果你需要一个条件而不是特定数量的调用失败,这可能不适用于你的情况,但我认为我会从最简单的方法开始):

    [Test]
    public void StubMultipleCalls() {
        Func<string> throwEx = () => { throw new Exception(); };
        var sub = Substitute.For<IThingoe>();
        // Stub method to fail twice, then return valid data
        sub.MethodToRetry(Arg.Any<string>())
           .Returns(x => throwEx(), x => throwEx(), x => "works now");

        // The substitute will then act like this:
        Assert.Throws<Exception>(() => sub.MethodToRetry("")); 
        Assert.Throws<Exception>(() => sub.MethodToRetry("")); 
        Assert.AreEqual("works now", sub.MethodToRetry(""));
        // Will continue returning last stubbed value...
        Assert.AreEqual("works now", sub.MethodToRetry(""));
        Assert.AreEqual("works now", sub.MethodToRetry(""));
    }

另一种选择是在调用时加入条件:

    [Test]
    public void StubWithCondition() {
        var shouldThrow = true;

        var sub = Substitute.For<IThingoe>();
        sub.MethodToRetry(Arg.Any<string>()).Returns(x => {
            if (shouldThrow) {
                throw new Exception();
            }
            return "works now";
        });

        Assert.Throws<Exception>(() => sub.MethodToRetry(""));
        shouldThrow = false; // <-- can alter behaviour by modifying this variable
        Assert.AreEqual("works now", sub.MethodToRetry(""));
    }

作为这种方法的修改版本,您还可以替换用于 stub 的回调:

    [Test]
    public void ReplaceLambda() {
        Func<string> methodToRetry = () => { throw new Exception(); };

        var sub = Substitute.For<IThingoe>();
        sub.MethodToRetry(Arg.Any<string>()).Returns(x => methodToRetry());

        Assert.Throws<Exception>(() => sub.MethodToRetry(""));
        methodToRetry = () => "works now";
        Assert.AreEqual("works now", sub.MethodToRetry(""));
    }

理想情况下,我们会尽量避免测试中依赖于时间的逻辑,但如果确实有必要,我们可以在 5 秒后更新第二个示例中的条件,以获得您问题中提到的行为。

关于c# - 如何在单元测试执行中更改方法的返回值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34709632/

相关文章:

C#等效排名

c# - 使用客户端对象模型的 Sharepoint 2010 用户身份验证(Windows 凭据)

c# - LINQ to NHibernate 和 let 关键字

c# - NUnit:如何从非静态方法传递 TestCaseData?

C# 页面回发

unit-testing - 如何对 Angular2 中的复选框进行单元测试

objective-c - 启用 "Defined Module"的 Xcode 单元测试目标中没有代码完成或语法突出显示

c# - 属性不能在 C++/CLI 中重复但在 C# 中可以吗?

visual-studio-2015 - Visual Studio 2015 测试资源管理器看不到 XUnit dnx 特征

c# - ReactiveUI 与 ICollectionView