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

Issue with selecting a constructor with null value #969

Closed
amir734jj opened this issue Feb 7, 2020 · 8 comments
Closed

Issue with selecting a constructor with null value #969

amir734jj opened this issue Feb 7, 2020 · 8 comments

Comments

@amir734jj
Copy link

I have the following setup and using Moq version 4.13.1. I am not sure this is a bug or not but I am wondering how can I get around this problem and pass null to the constructor argument.

public class Foo
{
    public Foo() { Console.Write("Foo() called"); }

    public Foo(string name, A _, Bar bar): this() { Console.Write("Foo(A) called"); }
    
    public Foo(string name, B _, Bar bar): this() { Console.Write("Foo(B) called"); }
}

public class A { }

public class B { }

public class Bar { }

class Program
{
    static void Main(string[] args)
    {
        // using default(A) will yield the same error
        var fooMock = new Mock<Foo>("Hello world!", (A) null, new Bar());

        var instance = fooMock.Object;
        
        Console.WriteLine(instance);
    }
}

I am getting the following error:

Unhandled exception. System.Reflection.AmbiguousMatchException:
Ambiguous match found.

Stacktrace:

   at System.DefaultBinder.BindToMethod(BindingFlags bindingAttr, MethodBase[] match, Object[]& args, ParameterModifier[] modifiers, CultureInfo cultureInfo, String[] names, Object& state)
   at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture)
   at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at Castle.DynamicProxy.ProxyGenerator.CreateClassProxyInstance(Type proxyType, List`1 proxyArguments, Type classToProxy, Object[] constructorArguments)
   at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors)
   at Moq.CastleProxyFactory.CreateProxy(Type mockType, IInterceptor interceptor, Type[] interfaces, Object[] arguments)
   at Moq.Mock`1.InitializeInstance()
   at Moq.Mock`1.OnGetObject()
   at Moq.Mock.get_Object()
   at Moq.Mock`1.get_Object()

Original StackOverFlow question

@canton7
Copy link

canton7 commented Feb 7, 2020

Note that this exception is expected. The missed opportunity is if you call:

var fooMock = new Mock<Foo>(() => new Foo("Hello, World", (A)null, new Bar()));

you still get the same exception, even though the constructor to call is known unambiguously.

(A workaround was already posted as an answer on SO)

@stakx
Copy link
Contributor

stakx commented Feb 9, 2020

I agree with @canton7, while there is no way to get this to work if you pass the ctor parameters via a params object[], using the lambda syntax should work. Needs more looking into, but I'll mark this as a bug in the meantime.

@stakx stakx added the bug label Feb 9, 2020
@amir734jj
Copy link
Author

@stakx Thanks for the follow-up. It would be an awesome feature.

@stakx stakx added dynamicproxy and removed bug labels Feb 17, 2020
@stakx
Copy link
Contributor

stakx commented Feb 17, 2020

Had a somewhat closer look, this isn't strictly a bug but a current limitation caused by DynamicProxy's API; see castleproject/Core#480.

@r-pankevicius
Copy link

@amir734jj I don't understand the real world situation why do you ever need this feature? I.e. using Mock(constructorArgs).

In most use cases I am familiar with all is around Moq Setup. In this situation you can use It.Is(a => a == null) or It.IsIn(null).

@stakx
Copy link
Contributor

stakx commented Aug 3, 2020

@r-pankevicius, this is about a mocked type's constructor, not its regular methods. You cannot set up a constructor; it will get called when instantiating a Mock<T> object.

In other words, you can only create setups when you have first created a Mock<T> instance. Imagine that the mocked type T is a class type that only has parameterized constructors. That means you'll need to provide constructor arguments to e.g. new Mock<T>(...). Only then will you have a mock on which you can setup other methods.

@r-pankevicius
Copy link

@stakx OK, I understood. I probably work in a very religious shop that separates interfaces from implementations. So I only have an experience mocking interfaces, not classes. Therefore I did not run into such issue.

@stakx
Copy link
Contributor

stakx commented Aug 26, 2021

Development over at the Castle DynamicProxy repo is a little slow-going these days, and I'm doubting that this issue with DynamicProxy will be fixed anytime soon. In the meantime, there's nothing we can do here, so I am going to close this issue for now... but I'll mark it as "unresolved" so that if and when DynamicProxy offers a way to select a specific constructor to use, we can easily find and reactive this present issue.

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

No branches or pull requests

4 participants