C# unit testing using mocks without interfaces

In order to properly unit test some of my classes I need to mock the class objects being used by the main class being tested. This is a simple process if all the objects being used implements the interface and I only need to use the methods form that interface. However, and here is the problem:

Interfaces are a contract on what other developers should expect in that class. Therefore all interface methods, properties etc. are public. Any good code should also have good encapsulation. Therefore I don’t want to make all methods in my class public and hence don’t declare it in the interface. And as a result I can not mock and setup these internal method that is used in my main class.

Other options I looked into was using an abstract class that can have different access modifiers and I can have the correct methods in it be internal or private etc. But since I want the class being mocked to be available is a public property of interface type for other developers to use, I need it be an interface, but now its not compatible anymore since my main class cant call the internal method anymore as its defined as an interface. Catch 22. (In case you were wondering, using virtual for methods will have the same problem as using an abstract class).

I have searched for similar questions regarding C# mocking and did not find the same problem I have. And please don’t be philosophical on “C# isn’t good language for testing” or such stuff. That’s not an answer.

Any ideas?

I added this code example to make it easier to see the problem described above.

[assembly: InternalsVisibleTo("MyService.Tests")]

public interface IMyService
{
    MethodABC()
    ...
}

public class MyService : IMyService 
{
    public void MethodABC()
    {
        ...
    }
    
    internal void Initialize()
    {
        ...
    }
    ...
}

public sealed partial class MyMain
{
    public IMyService Service { get; private set; }
    private MyService _service;
    
    ...
    
    private void SomeMethod()
    {
        // This method is in interface and can be used outside the project when this assembly is referenced
        _service.MethodABC() 
        ...
        
        // This method is and internal method inside the class not to be seen or used outside the project. 
        // 1) When running this method through unit test that mocked the IMyService will fail here since initialize don't exist which is correct.
        // 2) Mocking the MyService will require "virtual" to be added to all methods used and don't provide a interface/template for a developers if 
        //    they want to swap the service out.
        // 3) Changing the interface to abstract class and mocking that allows for making this an internal method and also set it up in mock to do 
        //    something for unit test and provides contract other developers can implement and pass in to use a different service, but requires 
        //    "override" for all methods to be used from "outside" this assembly. This is best solution but require changes to code for sole purpose
        //    of testing which is an anti-pattern.
        _service.Initialize() 
        ...
    }
}

// Unit test method in test project

[TestClass]
public class MyMainTests
{

    private Mock<IMyService> _myServiceMock = new Mock<IMyService>();

    [TestMethod]
    public void MyMain_Test_SomeMethod()
    {
        ...
        SomeMethod()
        ...
    }
}

Answer

Unfortunately there don’t seem to be a clean way of doing this. In order to create a mock using Moq, it needs to be either an interface, abstract class or virtual methods.

  • Interfaces cant have encapsulation lower than public. Using a internal interface will still force you to create “Public” methods.
  • Virtual methods allow access modifiers but do not provide an injectable object with a contract to be used by Moq other developers using the main class.
  • The ideal solution would not require code changes just for the purpose of making it unit testable. This unfortunately don’t seem to be possible.

Which brings me to an abstract class that can provide a template (semi interface) that can be handled like an interface but will require “override” for all contract methods but at least will allow correct access modifiers for methods.

This still goes against clean code as I will need to add code to all my methods for the sole purpose of making it unit testable.

This is something Microsoft can look into for new .Net C# features. I will check if they have a feature request for this already.

Leave a Reply

Your email address will not be published. Required fields are marked *