簡體   English   中英

當 arguments 與給定模式不匹配時,如何讓 NSubstitute 模擬失敗?

[英]How do I get NSubstitute mocks to fail when the arguments don't match the given pattern?

我負責測試我的團隊正在維護的在 C 和 C# 中開發的遺留軟件。 最初的團隊使用 NSubstitute 3.1 為代表創建測試替身,以便對 C# 部分的 API 執行單元測試。 這是一個這樣的測試替身,其中不相關的細節已被省略:

private static byte[] MockSelectByAidWithoutData(ushort retVal)
{
    var expectedIn= "FFFEFDFCFB".HexToBytes();
    var expectedOut= "010203040506070809".HexToBytes();

    var fake = Substitute.For<SomeDelegate>();
    fake(Arg.Is<byte[]>(x => expectedIn.SequenceEqual(x.Take(expectedIn.Length))),
            Arg.Is(0x00),
            Arg.Is(expectedIn.Length),
            Arg.Any<int>(),
            Arg.Any<int>(),
            out int outputLength)
        .Returns(x =>
            {
                expectedOut.CopyTo((Array)x[0], 0);
                x[5] = expectedOut.Length;
                return retVal;
            }
        );
    Mediator.GetInstance().Delegate = fake;
    return expectedOut;
}

現在,如果使用與fake()調用中指定的匹配的 arguments 調用假委托,它會返回retVal值,每個人都很高興。 但是,如果某些值不匹配,則返回零。 由於零是一個有效但不正確的值,執行繼續,我得到一個錯誤,這不是我正在測試的問題的根本原因(即當問題實際上是錯誤的輸入時,錯誤的 output)

我正在尋找一種方法:

  • 為不符合預期的值指定“全部捕獲”行為,或
  • 如果 arguments 不符合預期,則會出現異常

這樣測試用例會在接收到帶有有意義消息的錯誤輸入時立即失敗,並且不會觸發只會污染測試結果的進一步行為。

提前致謝,

德克

PS 如果真的有必要,我可能可以安全地切換到更新版本的 NSubstitute。

為不符合預期的值指定“全部捕獲”行為

我想我找到了一種方法可以做到這一點。 如果您首先為所有 arguments 存根“全部捕獲”/失敗案例,然后您可以存根更具體的調用。 NSubstitute 將嘗試匹配提供的最新規范,回退到較早的存根值。

這是一個示例。

請注意,它使用Configure 4.x 中引入的NSubstitute.Extensions命名空間中的配置。 這不是絕對必要的,因為如果您使用參數匹配器,NSubstitute 會自動假定您正在配置調用,但是在配置這樣的重疊調用時使用它是一個很好的模式。

using NSubstitute;
using NSubstitute.Extensions; // required for Configure()

public class Thing {
    public string Id { get; set; }
}

public interface ISample {
    int Example(Thing a, string b);
}

public class UnexpectedCallException : Exception { }

[Fact]
public void ExampleOfStubOneCallButFailOthers() {
    var sub = Substitute.For<ISample>();

    // Catch all case:
    sub.Example(null, null).ReturnsForAnyArgs(x => throw new UnexpectedCallException());

    // Specific case. We use Configure from NSubstitute.Extensions to
    // be able to stub this without getting an UnexpectedCallException.
    // Not strictly necessary here as we're using argument matchers so NSub
    // already knows we're configuring a call, but it's a good habit to get into.
    // See: https://nsubstitute.github.io/help/configure/
    sub.Configure()
        .Example(Arg.Is<Thing>(x => x.Id == "abc"), Arg.Any<string>())
        .Returns(x => 42);

    // Example of non-matching call:
    Assert.Throws<UnexpectedCallException>(() =>
        sub.Example(new Thing { Id = "def" }, "hi")
    );

    // Example of matching call:
    Assert.Equal(42, sub.Example(new Thing { Id = "abc" }, "hello"));
}

您可以擴展它以包含有關不匹配的 arguments 的信息,但這將是一些自定義工作。 如果您查看 NSubstitute 的一些參數格式化代碼,這些代碼可能可重用以幫助解決此問題。


更新以包含委托示例

我只是用一個委托來運行它,它也通過了:

public delegate int SomeDelegate(Thing a, string b);

[Fact]
public void ExampleOfStubOneDelegateCallButFailOthers() {
    var sub = Substitute.For<SomeDelegate>();
    sub(null, null).ReturnsForAnyArgs(x => throw new UnexpectedCallException());
    sub.Configure()
        .Invoke(Arg.Is<Thing>(x => x.Id == "abc"), Arg.Any<string>())
        .Returns(x => 42);
    Assert.Throws<UnexpectedCallException>(() => sub(new Thing { Id = "def" }, "hi"));
    Assert.Equal(42, sub(new Thing { Id = "abc" }, "hello"));
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM