Search code examples
c#countargumentsmoqinvocation

Moq invocation arguments changing in subsequent calls


In the following example I have a simple Service class which does something with it's input and a Processor which calls the Service.DoService() twice, passing the same InputParameters object, first x = 5, then x = 100; The problem is that in the unit tests I want to check if the DoService() method was called once with the original values (x==5) and once with the new values (x==100), but apparently it is called twice with x==100

      public class InputParameters
      {
         public int x, y;
      }

      public interface IService
      {
         bool DoSomething(InputParameters input);
      }

      public class Service : IService
      {
         public bool DoSomething(InputParameters input)
         {
            return input.x > input.y;
         }
      }

      public class Processor
      {
         public IService _service;

         public Processor(IService theServive)
         {
            _service = theServive;
         }

         public void Process()
         {
            InputParameters input = new InputParameters();
            input.x = 5;
            input.y = 50;

            _service.DoSomething(input);

            input.x = 100;
            _service.DoSomething(input);
         }

and the test

      private Mock<IService> _serviceMock;
      private Processor _processor;

      [SetUp]
      public void Setup()
      {
         _serviceMock = new Mock<IService>();
         _processor = new Processor(_serviceMock.Object);
      }

      [Test]
      public void Test()
      {
         _serviceMock.Setup(service => service.DoSomething(
            It.IsAny<InputParameters>()
         )).Returns(() => false);

         _processor.Process();

         _serviceMock.Verify(service => service.DoSomething(
            It.Is<InputParameters>(input => input.x == 5)
         ), Times.Exactly(1)); //returns 0 times called

         _serviceMock.Verify(service => service.DoSomething(
            It.Is<InputParameters>(input => input.x == 100)
         ), Times.Exactly(1)); //return 2 times calledd

I've debugged the execution and I can see that the first invocations arguments are changed when I call input.x = 100, and I do not understand how Moq keeps just a reference to the invocation arguments?

I've tried also a different setup, same result:

         _serviceMock.Setup(service => service.DoSomething(
            It.Is<InputParameters>(input => input.x == 5)
         )).Returns(() => true);

         _serviceMock.Setup(service => service.DoSomething(
            It.Is<InputParameters>(input => input.x == 100)
         )).Returns(() => false);

Code can be found here: https://github.com/rufusz/MoqInvocationCountIssue


Solution

  • I received answer officially from Moq: if the argument is a ref type, then this is expected behavior. If it's value type, it is copied in memory when the invocation arguments are stored, but this is not possible for ref types, for example file handles or window handles can create issues or are simply not (deep)clonable.