2

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?

Igor
  • 3,573
  • 4
  • 33
  • 55
  • 2
    You should define returned value for the mocked service `this.mockService.ServiceMethod(Arg.Any()).Returns(Result.With(Enumerable.Empty()))` – Fabio Nov 04 '18 at 03:44
  • Thanks Fabio! But I've tried that ... but I still have the same mistake. I updated the question. – Igor Nov 05 '18 at 23:08

1 Answers1

4

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!

David Tchepak
  • 9,826
  • 2
  • 56
  • 68
  • Thanks for the answer! But, before I wrote this question I had already tried everything you described (with `Returns()`, With real `Guid`). But the result is the same as described. This depends on the order of the tests are run ... if I put this problematic test as the first one to run, everything works fine. But other methods trigger the same exception. Would it be a reuse of memory? – Igor Nov 05 '18 at 23:15
  • Note: We remove the `Guid` parameter on `Backup` method. – Igor Nov 05 '18 at 23:23
  • 1
    Hi @Igor, I've updated my answer. Let me know how you go with it! :) – David Tchepak Nov 05 '18 at 23:39
  • Thanks David! I also have the package Analyzer in the project ... I just did not catch any problems. Does it throw the results in console output or only before compile?("Underlined lines"). Please, see the image on question. – Igor Nov 06 '18 at 00:03
  • @Igor Analyzer issues should be compiler warnings/errors starting with "NS" (so `NS1000` for example). That `AD0001` message should go away after building I think. Do you have Analyzers 1.0.1? That includes a fix for [this](https://github.com/nsubstitute/NSubstitute.Analyzers/issues/46). – David Tchepak Nov 06 '18 at 00:07
  • We using `` :\. When I put the test to be run first, like: `AAA_Test_Method ()` everything works... – Igor Nov 06 '18 at 00:14
  • 1
    @Igor Sorry for the trouble this is causing. What line is the stack trace pointing to? We might be better off moving this to https://github.com/nsubstitute/NSubstitute/issues so we can share more info (I'm not sure this works well as a SO q&a at this point). To provide assistance I think I'll need more info on the other tests in the fixture (it happens when you run the single fixture, correct?). If you can reproduce it with two or three tests in the fixture and post stripped down versions of the classes/interfaces involved then I think we have a good chance of identifying the problem. – David Tchepak Nov 06 '18 at 00:24
  • 1
    @Thank you for your help! Let's continue on github then! :) – Igor Nov 06 '18 at 00:30
  • 1
    Yesterday I scoured my entire test code to try to identify the problem, and I was able to understand what was happening :) There were more methods that used `Arg.` for real calls. I set them all, and everything worked fine! Thank you for your help! I would just like to understand why some tests work earlier :( ... But... – Igor Nov 06 '18 at 13:27
  • 1
    @Igor Glad you got it sorted! Depending on the test order some of the arg matchers can be cleared. The next NSubstitute release (4.0) aims to improve this by detecting these issues earlier. For a technical explanation of what is happening, try https://weareadaptive.com/2014/09/30/why-nsubstitute/ starting at the "NSubstitute tradeoffs" heading. – David Tchepak Nov 07 '18 at 00:38
  • ! Great article to explain the "problem"! Thanks for the info and keep up the great work! :) – Igor Nov 07 '18 at 13:01
  • 1
    @DavidTchepak thanks for poiting to NSubstitute.Analyzers. I had same problem that one test wasn't passing with AmbiguousArgumentsException but it was thrown in test class Setup not in a test. It didn't makes a sense for me because there ware no ambiguous argument types and it passes when run separately. Analyzer however pointed me to another test from that class which was trying to receive a call of not internal method. Changed the called method to internal and now everything works fine. – Gondil Aug 09 '19 at 09:10
  • 1
    I was facing a similar issue where the test would succeed when run individually but would fail if all tests were run simultaneously. "Arg.Any is only for substitutes" is the key. I found that some of the real calls had Args.Any in parameters. Removed all such cases from the code and everything works fine now. Thanks @Igor https://nsubstitute.github.io/help/argument-matchers/ – Sukanya1991 Jun 30 '21 at 14:54