How to mock Func<Enum, Interface>() parameter in constructor of the tested class (sut)

Viewed 34

In my .Net6 web app, I attempted to register service injection for 2 implementations of a single IWordRepository Interface:

  1. WordRepositoryInMemory, working with in-memory data;
  2. WordRepositoryDatabase with calls to the database;

Following the example set out in this article, I created an enum:

public enum WordRepositoryImplementation
{
    WordRepositoryInMemory,
    WordRepositoryDatabase
}

Then, in my Program.cs, I registered the two services:

builder.Services.AddScoped<WordRepositoryDatabase>();
builder.Services.AddScoped<WordRepositoryInMemory>();

builder.Services.AddTransient<Func<WordRepositoryImplementation, IWordRepository?>>(wordRepositoryProvider => key =>
{
    return key switch
    {
        WordRepositoryImplementation.WordRepositoryInMemory => wordRepositoryProvider.GetService<WordRepositoryInMemory>(),
        WordRepositoryImplementation.WordRepositoryDatabase => wordRepositoryProvider.GetService<WordRepositoryDatabase>(),
        _ => null,
    };
});

Then, I called it in my controller like so:

private readonly IWordRepository _wordRepositoryDatabase; // I only require one of the implementations to be called by this controller.

public DictionaryDataController(Func<WordRepositoryImplementation, IWordRepository> serviceResolver)
{
    _wordRepositoryDatabase = serviceResolver(WordRepositoryImplementation.WordRepositoryDatabase);
}

Unfortunately, this added complexity messed up my tests for the controller. I am no longer able to instantiate the sut with a simple Mock.Object of the WordRepositoryDatabase service. By saying unable, I mean that I don't quite have the required experience handling delegates, yet.

In my test fixture, I tried to replace the original mock implementation of the service:

private Mock<IWordRepository> _wordRepository;
// ....
_wordRepository= new Mock<IWordRepository>();
// ....
DictionaryDataController sut = new(_wordRepositoryDatabase.Object);

To something that returns a Mock of the IWordRepository, so that I could use it in my constructor:

private Func<WordRepositoryImplementation, IWordRepository?> _funcWordRepositoryImplementation;
// ...
// ...
DictionaryDataController sut = new(_funcWordRepositoryImplementation);

However, I cannot grasp the required syntax here. The closest I got to was a parameterless Func<>() that returned the Mock.Object, but it was clearly missing something.

_funcWordRepositoryImplementation= () =>
{
    return new Mock<WordRepositoryImplementation, IWordRepository>();
};

And attempts to pass some arguments to it caused their own set of errors.

What would the correct way to set up this field be?

1 Answers

Just use lambda expression with discard parameter which will return _wordRepositoryDatabase.Object:

DictionaryDataController sut = new(_ => _wordRepositoryDatabase.Object);
Related