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

Casting Mock To Interface Loses Value #175

Closed
aolszowka opened this issue May 29, 2015 · 3 comments
Closed

Casting Mock To Interface Loses Value #175

aolszowka opened this issue May 29, 2015 · 3 comments
Labels

Comments

@aolszowka
Copy link

After upgrading to Moq 4.2.1502.911 we are seeing what we believe is a bug in Moq when attempting to cast a mocked type to an Interface. We've produced a test case below along with a few unit tests.

namespace MoqBug
{
    using System.Collections.Generic;
    using System.Linq;
    using Moq;
    using NUnit.Framework;

    [TestFixture]
    public class FunWithTypes
    {
        [Test]
        public void MoqErrors()
        {
            Mock<ExtendingTypeBase> fake = new Mock<ExtendingTypeBase>(42);
            ExtendingTypeBase realFake = fake.Object;

            // Make sure we're telling the truth that the value is mocked prior to our frobbing
            Assert.That(realFake.ExtendedValue, Is.EqualTo(42));

            Frobber frobber = new Frobber(realFake);

            Assert.That(frobber.WasExtendedType, Is.True);
            // BUGBUG: Seems to have been set back to the default for this type (Moq type is by default LOOSE)
            Assert.That(frobber.ExtendedTypeValue, Is.EqualTo(42), "BUGBUG: Moq Lost the value and set back to default.");
        }

        [Test]
        public void CSharpIsCoolWithIt()
        {
            ExtendingTypeBase real = new ExtendedConcreteType(42);

            // Make sure we're telling the truth that the value is mocked prior to our frobbing
            Assert.That(real.ExtendedValue, Is.EqualTo(42));

            Frobber frobber = new Frobber(real);

            Assert.That(frobber.WasExtendedType, Is.True);
            Assert.That(frobber.ExtendedTypeValue, Is.EqualTo(42));
        }

        [Test]
        public void MoqErrorsTwo()
        {
            var rootMock = new Mock<ExtendingTypeBase>(42);
            ExtendingTypeBase realObject = rootMock.Object;
            IExtendedType realObjectInterfaceType = rootMock.Object;
            Assert.That(realObject.ExtendedValue, Is.EqualTo(42));
            // BUGBUG: Seems to have been set back to the default for this type (Moq type is by default LOOSE)
            Assert.That(realObjectInterfaceType.ExtendedValue, Is.EqualTo(42));
        }

        [Test]
        public void MoqErrorsThree()
        {
            var rootMock = new Mock<ExtendingTypeBase>(42);
            ExtendingTypeBase realObject = rootMock.Object;
            IExtendedType realObjectInterfaceType = rootMock.As<IExtendedType>().Object;
            Assert.That(realObject.ExtendedValue, Is.EqualTo(42));
            // BUGBUG: Seems to have been set back to the default for this type (Moq type is by default LOOSE)
            Assert.That(realObjectInterfaceType.ExtendedValue, Is.EqualTo(42));
        }
    }

    public class Frobber
    {
        List<ISharedType> internalStore;

        public Frobber(params ISharedType[] inputs)
        {
            // Save the Internal Store
            this.internalStore = new List<ISharedType>(inputs);
        }

        public bool WasExtendedType
        {
            get
            {
                return this.internalStore.First() is IExtendedType;
            }
        }

        public int ExtendedTypeValue
        {
            get
            {
                return ((IExtendedType)this.internalStore.First()).ExtendedValue;
            }
        }
    }

    public class ExtendedConcreteType : ExtendingTypeBase
    {
        public ExtendedConcreteType(int extendedValue):
            base(extendedValue)
        {
        }

        public override int CommonValue
        {
            get;
            set;
        }
    }

    public interface ISharedType
    {
        int CommonValue { get; set; }
    }

    public interface IExtendedType
    {
        int ExtendedValue { get; set; }
    }

    public abstract class ExtendingTypeBase : ISharedType, IExtendedType
    {
        public ExtendingTypeBase(int extendedValue)
        {
            this.ExtendedValue = extendedValue;
        }

        public abstract int CommonValue { get; set; }
        public int ExtendedValue { get; set; }
    }
}

Looking at the issues log I think it might be related to #164 and probably the root cause of #156 along with #162. I did a pull of the latest source and the issue is still present, however nothing was readily apparent in my debugging, but I'll admit I did not dig very deep.

The first scenario posted is more or less a very very stripped down version of something we have in our "production" test code, the remaining test cases are what some of our other developers came up with.

@stakx
Copy link
Contributor

stakx commented Jun 20, 2017

Fixed in Moq 4.7.58.

@stakx stakx closed this as completed Jun 20, 2017
@aolszowka
Copy link
Author

Wow I don't know why I wasn't notified of this fix back in 2017 but for some reason thought about coming back to this bug. You are awesome @stakx Doing some amazing work!

@stakx
Copy link
Contributor

stakx commented Jun 27, 2018

@aolszowka:

The issue was already fairly old when I closed it, perhaps GitHub muted it for that reason...?

However it may be... thank you for the kind words! Glad if I could help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants