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

Moq 1409 changes the behaviour of internals in a mocked class #132

Closed
OsirisTerje opened this issue Sep 18, 2014 · 2 comments
Closed

Moq 1409 changes the behaviour of internals in a mocked class #132

OsirisTerje opened this issue Sep 18, 2014 · 2 comments

Comments

@OsirisTerje
Copy link

OsirisTerje commented Sep 18, 2014

Just noted a change in the behaviour of Moq from 1402 to 1408.

Given a class Sut containing a another class that is ctor'ed with a Sut's this through an interface to Sut, and through that accesses some other contained class of Sut.
With 1402 this works fine.
With 1408 it crashes instead the other class when it accesses the interfaced this pointer, as what it points to will be null.

Even if this in intentional it doesn't seem right that it cares about the internals of the mocked class, since all the internals is constructed correctly in its ctor.

To make this easier to check, as the wording above might be confusing, I have enclosed a repro below. Test this with 1042, it works, with 1408 or 1409, it crashes with:
Test Name: CheckThis
Test FullName: MoqThisIssue.MoqChecks.CheckThis
Test Source: c:\Users\Terje\source\repos\MoqIssues\MoqThisIssue\Class1.cs : line 17
Test Outcome: Failed
Test Duration: 0:00:00.111

Result Message:
System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
----> System.NullReferenceException : Object reference not set to an instance of an object.
Result StackTrace:
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
at System.Activator.CreateInstance(Type type, Object[] args)
at Castle.DynamicProxy.ProxyGenerator.CreateClassProxyInstance(Type proxyType, List1 proxyArguments, Type classToProxy, Object[] constructorArguments) at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors) at Moq.Proxy.CastleProxyFactory.CreateProxy(Type mockType, ICallInterceptor interceptor, Type[] interfaces, Object[] arguments) at Moq.Mock1.b__2()
at Moq.PexProtector.Invoke(Action action)
at Moq.Mock1.InitializeInstance() at Moq.Mock1.OnGetObject()
at Moq.Mock`1.get_Object()
at MoqThisIssue.MoqChecks.CheckThis() in c:\Users\Terje\source\repos\MoqIssues\MoqThisIssue\Class1.cs:line 22
--NullReferenceException
at MoqThisIssue.Contained..ctor(ISut owner) in c:\Users\Terje\source\repos\MoqIssues\MoqThisIssue\Class1.cs:line 65
at MoqThisIssue.Sut..ctor() in c:\Users\Terje\source\repos\MoqIssues\MoqThisIssue\Class1.cs:line 39
at Castle.Proxies.SutProxy..ctor(IInterceptor[] )

The code is:

using Moq;
using NUnit.Framework;
namespace MoqThisIssue
{
    [TestFixture]
    public class MoqChecks
    {
        [Test]
        public void CheckThis()
        {
            AnotherClass anotherClass = new AnotherClass();
            var mockA = new Mock<Sut>();
            mockA.SetupGet(x => x.PropertyForTest).Returns(anotherClass);
            var retb = mockA.Object.PropertyForTest;
        }
    }

public interface ISut
{
    PartOfSut PartOfSut { get; }
}
public class Sut : ISut
{
    public virtual AnotherClass PropertyForTest { get; set; }
    private PartOfSut partOfSut;
    public Contained Contained { get; set; }
    public Sut()
    {
        partOfSut = new PartOfSut();
        Contained = new Contained(this);
    }
    public PartOfSut PartOfSut { get { return partOfSut; } }
}

public class PartOfSut
{
    public void DoSomething()
    { }
}

public class AnotherClass
{

}

public class Contained
{
    ISut Owner { get; set; }
    public Contained(ISut owner)
    {
        Owner = owner;
        y = Owner.PartOfSut;
        y.DoSomething();
    }

    private PartOfSut y;
}
}
@OsirisTerje
Copy link
Author

No answers, so I'll answer it myself then :-)
At least what I think has been going on.

In version 1402, the default value of the property CallBase was true, but in version 1408 that was changed to false.
So in order to make the code above work in 1408 you must set CallBase to true for the mock that is created.

Was this done deliberately or was it an accidental change ?

@stakx
Copy link
Contributor

stakx commented Jun 20, 2017

@OsirisTerje: This was an accidental change (see the PR linked to above) and is now fixed in Moq 4.7.58.

@stakx stakx closed this as completed Jun 20, 2017
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