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

Reference parameter in virtual method doesn't update correctly when class is mocked #585

Closed
iitaiy opened this issue Feb 6, 2018 · 1 comment

Comments

@iitaiy
Copy link

iitaiy commented Feb 6, 2018

I have test that check ref parameter value from event that raised after the change. The test work fine when I create real class but when I try mocked class its fail. Simple code example:

[TestClass]
public class Fixture
{
    [TestMethod]
    public void CheckRealClass()
    {
        // this test passed
        var classToTest = new NumberChangerClass();
        CheckClass(classToTest);
    }

    [TestMethod]
    public void CheckMockedClass()
    {
        // this test failed
        var classToTest = new Mock<NumberChangerClass>() { CallBase = true };
        CheckClass(classToTest.Object);
    }

    private void CheckClass(NumberChangerClass numberChangerClass)
    {
        // Arrange
        var number = 1;
        numberChangerClass.StorageChanged += (sender, args) =>
        {
            Assert.AreEqual(2, number);
        };


        // Act
        numberChangerClass.SetValue(ref number, 2);
    }
}

public class NumberChangerClass
{
    public event EventHandler StorageChanged;

    public virtual void SetValue(ref int storage, int newValue)
    {
        storage = newValue;
        StorageChanged?.Invoke(this, null);
    }
}

In CheckMockedClass the number is actually changed but only after the the code exits from SetValue method.

Thank you for the help.

@stakx
Copy link
Contributor

stakx commented Feb 6, 2018

Near-duplicate of #466.

@iitaiy, the behaviour you are observing is a direct consequence of how DynamicProxy (which Moq depends on) handles by-reference parameters during method call interception (which is documented at https://github.com/castleproject/Core/blob/master/docs/dynamicproxy-by-ref-parameters.md): Arguments are buffered in a separate location during call interception and only written back at the end of interception, that's why refparameters are updated in a delayed / deferred manner. There is unfortunately nothing that can be done about it.

Thank you for taking the time to report this, though!

@stakx stakx closed this as completed Feb 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants