Failure when invoking a method with by-ref parameter & mockable return type on a mock with CallBase
and DefaultValue.Mock
configured #1249
Description
NOTE: this is not a dupe of #1148 - my problem code is not using generics.
Apologies in advance if this is unclear - the tests in the repro solution I've attached should be more eloquent than my writing.
The repro uses AutoMoq because I haven't been able to trigger this issue in Moq directly, but the stack trace generated points directly to Moq as the culprit.
Describe the Bug
Given an object <OuterService>
That has a constructor dependency on an interface <InnerDependency>
And <InnerDependency>
defines a method that accepts a parameter decorated with the in
modifier
And <OuterService>
defines a method that calls the previously-mentioned method on <InnerDependency>
When attempting to AutoMoq <OuterService>
using the following:
var sut = new Fixture().Customize(new AutoMoqCustomization()).Create<<OuterService>>();
Moq 4.17.2 fails:
Message:
System.ArgumentException : Type must not be ByRef (Parameter 'type')
Stack Trace:
System.Dynamic.Utils.TypeUtils.ValidateType(Type type, String paramName, Boolean allowByRef, Boolean allowPointer)
System.Linq.Expressions.Expression.Constant(Object value, Type type)
Moq.MethodExpectation.CreateFrom(Invocation invocation)
Moq.Behaviors.ReturnBaseOrDefaultValue.Execute(Invocation invocation)
Moq.Return.Handle(Invocation invocation, Mock mock)
Moq.Mock.Moq.IInterceptor.Intercept(Invocation invocation)
Moq.CastleProxyFactory.Interceptor.Intercept(IInvocation underlying)
Castle.DynamicProxy.AbstractInvocation.Proceed()
<IInnerDependency>Proxy.DoSomething(Poco& poco)
<OuterService>.DoSomething(String input) line 16
<TestMethod>() line 26
but only if the in
parameter on <IInnerDependency> is a non-primitive object type - if you use string
, there is no exception (i.e. it works as expected)!
Based on the above stack trace it looks like this line is the problem. I think it needs to be changed to something like:
while (parameterTypes[i].HasElementType)
{
parameterTypes[i] = parameterTypes[i].GetElementType();
}
arguments[i] = E.Constant(invocation.Arguments[i], parameterTypes[i]);
I haven't pulled this repo's source and tried the above, but a quick console app I whipped up (included in the repro) uses this approach and seems to work.
Scenario
Attached. There are 2 tests:
- TestPoco: using a POCO as the
in
parameter (fails) - TestString: using a
string
as thein
parameter (passes)
Expected Behavior
The first scenario (dependency with POCO as in
parameter) works.