Search code examples
mockingnsubstitute

NSubstitute cannot determine argument specifications to use when "Run All Tests" of project


I have a test method:

public class MyTests
{
  [Fact]
  public void Test_Method()
  {
     // Arrange 
     var returns = Result.Ok(new List<string>() { "Test" }.AsEnumerable());  

     this.mockService.ServiceMethod(Arg.Any<Guid>()).Returns(returns); //returns Result<IEnumerable<string>>


     //Act
     var actResult = this.anotherService.Backup();

     //Assert
     Assert.True(actResult.Success);
  }
  ...

To test this method:

public class AnotherService
{

  internal Result Backup()
  {
    var ret = this.mockService.ServiceMethod().Value;

    ...

    return Result.Ok();
  }

When I run the method only for Test_Method() everything happens fine. When I try to run for the entire MyTests class I get the following error on this refer method:

NSubstitute.Exceptions.AmbiguousArgumentsException: 'Cannot determine argument specifications to use. Please use specifications for all arguments of the same type.'

I believe this problem has nothing to do with this scenario: How NOT to use argument matchers

NSubstitute.Analyzers:

NSubstitute.Analyzers

Is there anything to do?


Solution

  • Update after comments and question update:

    If there are still problems after making the changes from my original answer it may be another test in the fixture that is causing a problem. I recommend adding NSubstitute.Analyzers to the project which can pick up potential issues with NSubstitute usage at compile time using Roslyn. (I recommend adding this to all projects using NSubstitute; it can really help avoid a lot of potential problems!)

    If NSubstitute.Analyzers does not find the error then unfortunately we're just left with some manual steps as described in this answer.


    Original answer:

    Argument matchers need to be used in conjunction with specifying a call or asserting a call was received.

    The test you've posted has two places that could be causing this problem:

    • As @Fabio mentioned in a comment, an argument matcher is used in mockService.ServiceMethod() without a corresponding .Returns.
    • An argument matcher is used for a real call to anotherService.Backup()

    Try amending the test like this:

      [Fact]
      public void Test_Method()
      {
         // Arrange       
         this.mockService.ServiceMethod(Arg.Any<Guid>()).Returns(...);
         //                               ^- Arg matcher   ^- so need Returns()
    
         //Act
         var actResult = this.anotherService.Backup(Guid.NewGuid());
         //         Do not use arg matchers for real calls -^
    
         //Assert
         Assert.True(actResult.Success);
      }
    

    There may be another cause of this issue within your fixture, but these two uses of argument matchers will definitely not be helping!

    These problems are described in the argument matcher documentation you mentioned; if the documentation is unclear on these points please raise an issue with any suggestions for improving this section. It's really useful to get input on documentation from other perspectives, so any contribution you can make in this regard will be much appreciated!