Partial mocking class internal method with Moq

I have a class that contains a public method that relies on an internal method to correctly return its value.

Consider the following class and test file:

public class ClassUnderTest { public string NotMockedPublicMethod() { return MockedMethod(); } virtual public string MockedMethod() { return "original"; } } 

The following test case will work:

 var mock = new Mock<ClassUnderTest> { CallBase = true }; mock.Setup(m => m.MockedMethod()).Returns("mocked"); Assert.AreEqual("mocked", mock.Object.NotMockedPublicMethod()); 

But let's say that this MockedMethod() mine is not useful from the outside. The problem is that marking this method as internal (even if InternalsVisibleTo() used correctly):

 virtual internal string MockedMethod() 

will cause the exact same test to complete with the message Assert.AreEqual failed. Expected:<mocked>. Actual:<original> Assert.AreEqual failed. Expected:<mocked>. Actual:<original> Assert.AreEqual failed. Expected:<mocked>. Actual:<original> .

Is this a Moq bug or some limitation?

+6
source share
1 answer

This is not a mistake or limitation. Your test failed after the method was built in (even after adding InternalsVisibleTo) because it does not call the bullying method, but calls the actual method.

You need to add InternalsVisibleTo for DynamicProxyGenAssembly2 , as well as the address below.

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

http://www.blackwasp.co.uk/MoqInternals.aspx

Url does not give the correct explanation, but here it is:

Moq uses Project DynamicProxy Lock to create proxies on the fly at runtime so that members of the object can be intercepted without changing the class code. That Moq returns the value specified in "Setup (). Returns" (String "mocks" in your case)

Dynamic proxy address: http://www.castleproject.org/projects/dynamicproxy/

I looked at the source code (see below) for DynamicProxy, and I see that it uses "DynamicProxyGenAssembly2" as the assembly name for the generated assembly, and so you need to add InternalsVisibleTo for DynamicProxyGenAssembly2.

 public static readonly String DEFAULT_ASSEMBLY_NAME = "DynamicProxyGenAssembly2"; 

https://github.com/castleproject/Castle.DynamicProxy-READONLY/blob/ed8663b23a54bed641e5f97e39a6bc16fe0d976f/src/Castle.DynamicProxy/ModuleScope.cs

+12
source

All Articles