Search code examples
c#unit-testingmoq

How to mock classes with internal constructors and static factory method?


I have class MyService that depends on ABCService (Nuget package/sdk)

public class MyService
{
   private readonly ABCService _abc;

   public MyService(ABCService abc)
   {
      this._abc = abc;
   }

   public async Task Run(string id) 
   {
      // some logic
      var result = await this._abc.DoSomething(id);
      // some logic
   }
}

ABCService looks something like this:

public class ABCService 
{
   internal ABCService(string someConnectionString, object someSettings)
   {
      // ... initialization
   }

   public static CreateFromConnectionString(string someConnectionString, object someSettings)
   {
      // some logic
      return new ABCService(someConnectionString, someSettings);
   }
}

Mocking class this way would not work and throws exception. "Parent does not have a default constructor."

var mock = new Mock<ABCService>();
var myService = new MyService(mock.Object);

How should I approach this? Is there a way to mock such classes?

The only thing that comes to my mind is creating interface IABCService and then injecting it in the constructor of MyService

public class IABCService 
{
   Task DoSomething(string id);
}

public class MyService
{
   private readonly IABCService _abc;

   public MyService(IABCService abc)
   {
      this._abc = abc;
   }
}

And then I could do this:

var mock = new Mock<IABCService>();
var myService = new MyService(mock.Object);

Solution

  • Popular isolation frameworks such as Moq, NSubstitute or FakeItEasy are constrained. They can substitute only virtual methods. To use them, you will have to use the interface, as you already guessed. This is the recommended way to easily maintain loose coupling and testability.

    There are bunch of unconstrained mocking frameworks: TypeMock Isolator, JustMock, Microsoft Fakes (all three are paid) and free open source Prig, Pose, Shimmy, Harmony, AutoFake, Ionad.Fody, MethodRedirect. They allow to mock non-virtual members, including private, static, etc.
    Some of them allow you to work wonders, but you should not get too carried away with using them, because in the end it can lead to bad architecture.