Autofixture create object with static Lazy instanciation

1.1k Views Asked by At

I have a service class I'm trying to test and I'm hitting some difficulties

This class has a private constructor so it necessitate to be created from the static Instance property returning a Lazy _singleton value.

public class MyService : IMyService
{
    private static readonly Lazy<IMyService> _singleton = new Lazy<IMyService>(() => new MyService(new InjectedService()));
    public static IPermissionService Instance = _singleton.Value;

    private readonly IInjectedService _injectedService;

    private MyService(IInjectedService injectedService) => _injectedService = injectedService;


    // instance method I want to test
    public void DoSomething()
    {

    }
}

I'm trying to use AutoFixture and AutoMoq to create my object, using the Create() method, but it keeps complaining I have no public constructor. If I set this constructor public, I still get an error that seems to come from the Lazy func.

Could anyone help? I'm probably having different kind of design issues. I don't know if it can be fixed easily.

Edit 1: I don't have any IoC container so I can register my service as a singleton. I was trying to use this method to simulate an injection of the dependency service so I can write tests with mocks.

I have made some progress, but I'm not sure I like it either... Anyway I'll share what I have

public static class My
{
    private static readonly Lazy<IMyService> _singleton = new Lazy<IMyService>(() => new MyService(new InjectedService()));
    public static IPermissionService Service = _singleton.Value;
}

public class MyService : IMyService
{
    private readonly IInjectedService _injectedService;

    public MyService(IInjectedService injectedService) => _injectedService = injectedService;


    // instance method I want to test
    public void DoSomething()
    {

    }
}

This way I can build my class with AutoFixture and Freeze a mock of the injectedService.

And I can use the static class this way

My.Service.DoSomething();

And in my tests

Fixture.Freeze<Mock<IInjectedService>>().Setup(...);
var service = Fixture.Create<MyService>();

service.DoSomething();
// assert my things
1

There are 1 best solutions below

0
On

It's a bit less like using an auto-mocking container than you might like, but property (bastard) injection should get you there.

Depending on access requirements, marking a static property as internal may or may not help future readers, but since you're pretty quick to make changes allowing the instance class to be created outside the singleton pattern it seems as though you would be fine with it.

If you add a static property through which the dependency can be injected you can change your singleton initializer to use its value (bastard injection: if it has one).

public class MyService : IService
{
  private static readonly Lazy<IService > _singleton = new Lazy<IService >(() => new 
  MyService(MyDependency ?? new BastardizedInjectable()));
  public static IService Instance = _singleton.Value;

  internal static IMyDependency MyDependency 
  { 
    get;
    set;
  }

  private readonly IMyDependency _injectedService;

  private MyService(IMyDependency injectedService) => _injectedService = injectedService;


  // instance method I want to test
  public void DoSomething()
  {
    var stuff = _injectedService.GetStuff();
  }
}

With this implementation, your test(s) should be able to do something like:

fixture.Customize<MyService>(c => c.FromFactory(() => MyService.Instance));
var depMock = fixture.Freeze<Mock<IMyDependency>>();
MyService.MyDependency = depMock;
var sut = fixture.Create<MyService>();

Bastard injection is often referred to as an anti-pattern, or at least going against the D in SOLID (Dependency Inversion). If you're confident that this property can be relied upon to be injected from comp-root, then you should just bite the bullet and remove the ?? new BastardizedInjectable(). Future you will thank you.