0

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
Noone
  • 395
  • 1
  • 4
  • 17
  • 1
    I found [a similar question](https://stackoverflow.com/questions/18307975/autofixture-constructer-injection-lazy-loading). I suggest using Dependency Injection and registering MyService as a Singleton. – Emil Terman Mar 31 '20 at 21:16
  • Please share a [mcve] of your (AutoFixture) progress so far. – mjwills Mar 31 '20 at 21:22
  • Which IoC container are you using? – mjwills Mar 31 '20 at 21:23
  • I actually don't have any container in this project and would need a great effort to add one, hence the Instance property – Noone Mar 31 '20 at 22:36
  • I have done some progress splitting in two classes, one with the static elements and the service class, with a public constructor – Noone Mar 31 '20 at 22:39
  • `would need a great effort to add one` IoC can be layered in a little bit of a time, using it effectively as a service locator. I'd suggest starting with that. – mjwills Apr 01 '20 at 03:10
  • @mjwills I'm not sure how it could be achieved, I would need to configure a container and create a singleton "ServiceLocator" ? this service locator would need to be accessed from different assemblies... I'll try to find some examples... – Noone Apr 01 '20 at 12:19
  • https://autofaccn.readthedocs.io/en/latest/integration/csl.html perhaps? – mjwills Apr 01 '20 at 12:22
  • Thanks, I'll have a look – Noone Apr 01 '20 at 12:30
  • @mjwills Nice it's working, except, I will have to use ServiceLocator.Current.GetInstance<>() every place I need the injected services right? Let's say one day everything is configured I will need to go through each to remove them and use the one injected from constructor? – Noone Apr 01 '20 at 12:55
  • Basically yes.. – mjwills Apr 01 '20 at 13:06

1 Answers1

0

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.

Josh Gust
  • 4,102
  • 25
  • 41