lundi 27 juin 2016

Moq verify uses objects modified in Returns, rather than what was actually passed in

Background

I have a class that uses NHibernate to persist objects to a database. When you call MergeEntity for an object that does not have an ID set, NHibernate populates that object with an ID when it is returned. In order to make sure I always use the same object as NHibernate is using, I pass that updated object back from my "Save" function.

Problem

I am trying to mock that same behavior using Moq, which is usually very intuitive and easy to use; however, I am having some trouble verifying that the calls to Save() are being made with the correct arguments. I would like to verify that the ID of the object being passed in is zero, then that it is set properly by the Save function. Unfortunately, when I modify the ID in the Moq.Returns() function, the Moq.Verify function uses the modified value rather than the value of the ID that was passed in.

To illustrate, here is a very basic class (I override the ToString() function so my test output will show me what ID was used when the mocked Save() is called):

public class Class1
{
    private readonly IPersistence _persistence;

    /// <summary>Initializes a new instance of the <see cref="T:System.Object" /> class.</summary>
    public Class1(IPersistence persistence)
    {
        _persistence = persistence;
    }

    public int Id { get; set; }

    public void Save()
    {
       _persistence.Save(this);
    }

    public override string ToString()
    {
        return Id.ToString();
    }
}

Here is the Interface (very straight forward):

public interface IPersistence
{
    Class1 Save(Class1 one);
}

And here is the test that I think should pass:

[TestFixture]
public class Class1Tests
{
    [Test]
    public void Save_NewObjects_IdsUpdated()
    {
        var mock = new Mock<IPersistence>();
        mock.Setup(x => x.Save(It.IsAny<Class1>()))
            .Returns((Class1 c) =>
            {
                // If it is a new object, then update the ID
                if (c.Id == 0) c.Id = 1;

                return c;
            });

        // Verify that the IDs are updated for new objects when saved
        var one = new Class1(mock.Object);

        Assert.AreEqual(0, one.Id);

        one.Save();

        mock.Verify(x => x.Save(It.Is<Class1>(o => o.Id == 0)));
    }
}

Unfortunately, it fails saying that it was never called with arguments that match that criteia. The only invocation to Save that was made on the mock is with an object that had an ID of 1. I have verified that the objects have an ID of 0 when they enter the Returns function. Is there no way for me to distinguish what was passed into the mock from what those objects are updated to be if I update the values in my Returns() function?

Aucun commentaire:

Enregistrer un commentaire