NSubstitute
NSubstitute copied to clipboard
`Arg.Any<T>()` behaves strangely when it's stored in a variable instead of being passed directly
Describe the bug
The effect of Arg.Any<T>() depends on whether it's stored in a variable or passed directly.
To Reproduce
public interface INumberChecker
{
public bool Exists(int num);
}
public class MyApp
{
private readonly INumberChecker _numberChecker;
public MyApp(INumberChecker myInterfaceImpl)
{
_numberChecker = myInterfaceImpl;
}
public void CheckIfNumberExists(int num)
{
_numberChecker.Exists(num);
}
}
[Fact]
public void MinimalReproducibleExample()
{
var sub = Substitute.For<INumberChecker>();
var anyInt = Arg.Any<int>(); //storing this as a variable here..
sub.Exists(anyInt).Returns(true); //..and using it here
var app = new MyApp(sub);
app.CheckIfNumberExists(1);
sub.DidNotReceive().Exists(anyInt); //..and here
}
Expected behaviour
With the given code, I'd expect the test to fail, since sub does receive a call to its Exists(). However, the test passes.
However, if I pass Arg.Any<int>() directly to the methods it's used in, I get expected behaviour (i.e. an error saying that Exists() was called):
[Fact]
public void MinimalReproducibleExample()
{
var sub = Substitute.For<INumberChecker>();
sub.Exists(Arg.Any<int>()).Returns(true); //return value doesn't matter here
var app = new MyApp(sub);
app.CheckIfNumberExists(1);
sub.DidNotReceive().Exists(Arg.Any<int>());
}
Environment:
- NSubstitute version: [5.1.0]
- NSubstitute.Analyzers version: [CSharp 1.0.16]
- Platform: [dotnet 6.0 on Windows, XUnit]
Additional context
- Didn't find this covered in https://nsubstitute.github.io/help/argument-matchers/#how_not_to_use_argument_matchers
- Analyzer didn't pick up any problems.