【问题标题】:NSubstitute cannot determine argument specifications to useNSubstitute 无法确定要使用的参数规范
【发布时间】:2016-03-24 14:20:42
【问题描述】:

我使用 NUnit 和 NSubstitute 进行单元测试。我有以下内容:

public interface IDataProvider
{
    void Log(int tvmId, DateTime time, int source, int level, int eventCode, string message);
}

...

var fakeDataProvider = Substitute.For<IDataProvider>();
...
fakeDataProvider.Received().Log(
    Arg.Any<int>(),
    new DateTime(2000, 1, 1),
    0,
    0,
    0,
    null);

fakeDataProvider.Received() 抛出 AmbiguousArgumentException 并显示无法确定要使用的参数规范的消息。我在 SO 上找到了以下内容

Cannot determine argument specifications to use

这是相关的,但我不能在上面的代码中应用它。为什么上面的代码模棱两可?我还能如何向 Received() 指定它应该接受任何参数?

【问题讨论】:

    标签: c# mocking nsubstitute


    【解决方案1】:

    由于Log 方法中有多个int 参数,因此您必须对每个参数都使用参数规范。

    fakeDataProvider.Received().Log(
        Arg.Any<int>(),
        new DateTime(2000, 1, 1),
        Arg.Is(0),
        Arg.Is(0),
        Arg.Is(0),
        null);
    

    【讨论】:

    • 谢谢。我认为 Arg.Any() 是罪魁祸首,因为只有在我使用它时才抛出异常。
    • 确实如此。但问题并不完全在于 Arg.Any,而在于您使用 Arg.Any 的参数类型。由于还有其他相同类型的参数,NSubstitute 不知道您请求哪个是 Arg.Any,因此您必须为所有相同类型的参数指定参数规范。
    • @MarcioRinaldi 这个错误信息对我来说没有意义,因为方法参数的类型是由方法本身定义的。当该名称只有一个方法时(这是最典型的情况),它不应该写这个愚蠢的错误。我只有空参数值有问题,因为null没有输入,所以必须写Arg.Is&lt;string&gt;((string)null)
    • 参数规范的工作方式是创建一个列表,其中包含所有规范的调用顺序,然后根据调用的类型和顺序推断哪个规范与哪个参数相关。如果您有两个具有相同类型的参数,但只有一个使用了规范,那么您无法确定要为哪一个提供规范。它没有关于它用于哪个参数的信息。也许这个例外可以更好地措辞,但这是不可避免的。顺便说一句,您应该可以只使用null 而不是Arg.Is&lt;string&gt;((string)null)
    【解决方案2】:

    好吧,另一个针对年轻玩家的陷阱:如果您在一个测试中多次调用同一个方法,请不要在调用之间重复使用参数说明符:

    我有一个需要两个 Dictionary 的虚拟方法:

    var checkArg1 = Arg.Is<Dictionary<string, MyStruct>>(dico => dico.Count == 0);
    var checkArg2 = Arg.Is<Dictionary<string, MyStruct>>(dico => dico.Count == 0);
    mySubtitue.Received(1).myMethod(checkArg1, checkArg2);
    
    // do something that triggers another call to MyMethod 
    // ...
    
    // second check using the same argument specifiers
    mySubtitue.Received(1).myMethod(checkArg1, checkArg2);
    

    您仍然会收到“请对同一类型的所有参数使用规范”。

    解决方法是每次实例化参数说明符:

    var checkArg1 = Arg.Is<Dictionary<string, MyStruct>>(dico => dico.Count == 0);
    var checkArg2 = Arg.Is<Dictionary<string, MyStruct>>(dico => dico.Count == 0);
    mySubtitue.Received(1).myMethod(checkArg1, checkArg2);
    
    // do something that triggers another call to MyMethod 
    // ...
    
    // second check using new argument specifiers
    checkArg1 = Arg.Is<Dictionary<string, MyStruct>>(dico => dico.Count == 0);
    checkArg2 = Arg.Is<Dictionary<string, MyStruct>>(dico => dico.Count == 0);
    mySubtitue.Received(1).myMethod(checkArg1, checkArg2);
    

    【讨论】:

      【解决方案3】:

      您可以使用下面的代码来做到这一点

      fakeDataProvider.Received().Log(
          Arg.Any<int>(),
          new DateTime(2000, 1, 1),
          Arg.Is(0),
          Arg.Is(0),
          Arg.Is(0),
          null);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多