David Anderson
David Anderson

Reputation: 13670

How do you mock an abstract class containing an internal abstract method using Moq?

I have class A that I am unit testing a method on that takes class B as a parameter. Class B is what I am trying to mock out, and it is an abstract class. The class is similar to below.

public abstract class B
{
    internal abstract void DoSomething();
}

My unit test looks like.

[TestMethod]
public void ClassA_Add_TestSomething()
{
    var classA = new A();
    var mock   = new Mock<B>();

    classA.Add(mock.Object);

    // Assertion
}

I receive the following exception.

Test method TestSomething threw exception:
System.ArgumentException: Type to mock must be an interface or an abstract or non-sealed class. ---> System.TypeLoadException: Method 'DoSomething' in type 'Castle.Proxies.BProxy' from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.

I can get around this by making the method virtual instead of abstract, but that is not what I want to accomplish with the API design. I have also tried providing it a implementation through mock.Setup(m => m.DoSomething()) to no avail. Is this possible with Moq, or am I going to have to create a concrete test class that derives from the abstract class B? I wanted to avoid creating concrete types, which kind of defeats some of the purpose of using a mocking or stubbing framework, or am I mislead here?

Edit I have discovered that if I make the method public abstract this issue does not occur. So I guess the real question is if this is even possible with an internal method when using InternalsVisibleTo and Moq.

Upvotes: 7

Views: 5148

Answers (2)

Mike Zboray
Mike Zboray

Reputation: 40818

Consider carefully why you have an internal abstract method on a public class. Others will not be able to implement the abstract method because it is not visible to them. Perhaps this is what you want. Sometimes, given various design constraints, this is a valid approach. If your library is going to be consumed by others, I would recommend at least making the constructors internal as well so no one gets the idea that they could implement the abstract class.

Upvotes: 3

Gabriel Boya
Gabriel Boya

Reputation: 771

Moq relies on Castle Dynamic Proxy to implement its mocks. At runtime, a new assembly is created and loaded into your AppDomain by Moq (the name DynamicProxyGenAssembly2 that appears in the exception message).

The issue is that this assembly cannot access internal classes and members of your own code, because they are not visible outside the assembly where you declared them.

A workaround is to mark your assembly with the InternalsVisibleToAttribute and specify the name of the dynamically generated assembly :

[InternalsVisibleTo("DynamicProxyGenAssembly2")]

Remember however that this solution relies on an implementation detail, and might stop working in future versions.

Upvotes: 7

Related Questions