Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Erroneous "UnexpectedArgumentMatcherException" being received #450

Closed
davidgouldtracsis opened this issue Sep 7, 2018 · 5 comments
Closed
Labels
question Question on NSubstitute behaviour

Comments

@davidgouldtracsis
Copy link

Describe the bug
We are receiving a UnexpectedArgumentMatcherException when running a test which has previously passed repeatedly without any issues. We cannot see any logical reason why this exception is being thrown.

To Reproduce

[TestFixture]
public class Tests
{
    private ITcpClient _mockTcpClient;

    [SetUp]
    public void SetUp()
    {
        _mockTcpClient = Substitute.For<ITcpClient>();

        ITcpClientFactory mockTcpClientFactory = Substitute.For<ITcpClientFactory>();
        mockTcpClientFactory.Create().Returns(_mockTcpClient);
        ...
    }

where

public interface ITcpClientFactory
{
    ITcpClient Create();
}

The exception is thrown whilst mocking out the Create method.

Expected behaviour
No exception should be thrown, and the method should be mocked.

Environment:

  • NSubstitute version: [e.g. 3.1.0]
  • Platform: dotnetcore2.1 project on Win64

Additional context
We suspect that this may be a test bleed issue. There are 5 tests in the same Test Fixture which pass without issue; it is only one of these tests that pass.

Perhaps there is a threading issue somewhere, or some shared state?

@dtchepak
Copy link
Member

dtchepak commented Sep 7, 2018

Sorry you are having this issue. These are normally caused by a test bleed issue, normally due to an argument matcher being accidentally used with a non-virtual call, or being used with a normal call rather than an assertion or stub (as described here). These can be frustrating to track down unfortunately.

The first thing worth trying is installing the NSubstitute.Analyzers.CSharp beta package. This will pick up cases of substituting for virtual members. It does not catch all arg matchers problems, but I think it is worth trying out.

If that doesn't work, the next thing is to work out which test is running immediately prior to the one that is failing. I am assuming the test always passes when run on its own (please correct me if that is wrong!). Try running the entire fixture and checking test logs to see which ones run before the failing one. Alternatively, try commenting out combinations of tests in the fixture and see which one or ones you need to keep in order to trigger the problem. In the very worst case, this could be in the fixture that runs prior to this one in your test suite!

Once you have narrowed down the problem as much as possible, you want to look for all uses of Arg.* methods (.Is, .Any, .Do etc.). Make sure that each one is used when configuring or asserting on a substitute (never with a concrete class that is not a substitute, and never with non-virtual methods!). For example:

// INCORRECT: Using arg matcher as a normal value
var sampleArg = Arg.Any<int>();
// INCORRECT: Using arg matcher with a non-substitute
var myClass = new MyRealClass(Arg.Any<int>());
var myOtherClass = new MyRealClass();
myOtherClass.realCall(Arg.Any<int>());
// INCORRECT: Using arg matcher with a non-virtual (should be picked up by NSub.Analyzers)
var sub = Substitute.For<MyRealClass>();
sub.nonVirtualCall(Arg.Any<int>());

// CORRECT: used with assertion
sub.Received().VirtualCall(Arg.Any<int>());
// CORRECT: used with stub
sub.VirtualCall(Arg.Any<int>()).Returns("hello world");

I think it is less likely to be a threading issue due to NSub's use of threadlocal state and concurrent collections, so have a look for these arg matcher cases first.

Please let us know how you go. If you can't track down the issue then we'll get some more info from you and look into it further.

Best of luck, and sorry for the trouble!

@alexandrnikitin alexandrnikitin added the question Question on NSubstitute behaviour label Dec 28, 2018
@alexandrnikitin
Copy link
Member

@davidgouldtracsis I'm closing this but feel free to reopen if you still have the issue. We are happy to help.

@noamyogev84
Copy link

noamyogev84 commented Jul 5, 2019

Hi,
I also experienced the same issue.
Thanks @dtchepak for your detailed explanations.

My problematic behavior was caused by trying to create a REAL object while passing to the ctor Is.Any matcher instead of Substitute.For<>

@dtchepak
Copy link
Member

dtchepak commented Jul 8, 2019

@noamyogev84 Glad it helped and that you got it sorted! :)

@QHQuach
Copy link

QHQuach commented Nov 19, 2020

I ran into similar issue where a given test fails or passes sporadically depends on how it is ran. When running the failed test by itself, it always works. Running it from the class level together with others within the same test class, it always fails.

I installed the Analyzer as suggested. It found an arg matcher problem in a different test within the same class that always passes. Fixed that and all tests are now passing. Very weird and causing red-hearing.

Just want to share in case you are scratching your head on same thing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Question on NSubstitute behaviour
Projects
None yet
Development

No branches or pull requests

5 participants