You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug
It seems nsubstitute records all calls by reference rather than cloning the object.
To Reproduce
Run the XUnit test below.
Expected behaviour
All tests should pass. Or we should have a code analyzer hinting us that .Received(1) with argument matcher on reference types can have unexpected behaviour.
Environment:
NSubstitute version: [5.1.0]
NSubstitute.Analyzers version: [CSharp 1.0.17]
Platform: [net8 windows10]
Reproducing test
using System;
using System.Linq;
using NSubstitute;
using Xunit;
using Xunit.Abstractions;
namespace UnitTests.Tests;
public class GetArgumentsTest(ITestOutputHelper testOutputHelper)
{
[Fact]
public void ArgumentMatcher_OnSameInstance_ValueType()
{
var substitute = Substitute.For<IObjectUnderTest>();
var value = "initialValue";
substitute.Foo(value);
value = "newValue";
substitute.Foo(value);
var args = substitute.ReceivedCalls().SelectMany(x => x.GetArguments());
testOutputHelper.WriteLine(string.Join(", ", args));
}
[Fact]
public void ArgumentMatcher_OnSameInstance_ReferenceType_SameInstance()
{
var substitute = Substitute.For<IObjectUnderTest>();
var value = new MyReferenceType { Value = "initialValue"};
substitute.Foo(value);
value.Value = "newValue";
substitute.Foo(value);
var args = substitute.ReceivedCalls().SelectMany(x => x.GetArguments());
testOutputHelper.WriteLine(string.Join(", ", args));
substitute.Received(1).Foo(Arg.Is<MyReferenceType>(x => x.Value == "initialValue"));
substitute.Received(1).Foo(Arg.Is<MyReferenceType>(x => x.Value == "newValue"));
}
[Fact]
public void ArgumentMatcher_OnSameInstance_ReferenceType_NewInstance()
{
var substitute = Substitute.For<IObjectUnderTest>();
var value = new MyReferenceType { Value = "initialValue"};
substitute.Foo(value);
value = new MyReferenceType { Value = "newValue"};
substitute.Foo(value);
var args = substitute.ReceivedCalls().SelectMany(x => x.GetArguments());
testOutputHelper.WriteLine(string.Join(", ", args));
substitute.Received(1).Foo(Arg.Is<MyReferenceType>(x => x.Value == "initialValue"));
substitute.Received(1).Foo(Arg.Is<MyReferenceType>(x => x.Value == "newValue"));
}
}
public class MyReferenceType
{
public override string ToString()
{
return $"{nameof(Value)}: {Value}";
}
public string Value { get; set; }
}
public interface IObjectUnderTest
{
public void Foo(object argument);
}
The text was updated successfully, but these errors were encountered:
[Fact]
public void ArgumentMatcher_OnSameInstance_ReferenceType_SameInstance()
{
var values = new List<string>();
var substitute = Substitute.For<IObjectUnderTest>();
substitute.WhenForAnyArgs(s => s.Foo(Arg.Any<MyReferenceType>()))
.Do(c =>
{
var reference = c.ArgAt<MyReferenceType>(0);
values.Add(reference.Value);
});
var value = new MyReferenceType { Value = "initialValue" };
substitute.Foo(value);
value.Value = "newValue";
substitute.Foo(value);
values.Should().BeEquivalentTo(["initialValue", "newValue"]);
}
Describe the bug
It seems nsubstitute records all calls by reference rather than cloning the object.
To Reproduce
Run the XUnit test below.
Expected behaviour
All tests should pass. Or we should have a code analyzer hinting us that .Received(1) with argument matcher on reference types can have unexpected behaviour.
Environment:
Reproducing test
The text was updated successfully, but these errors were encountered: