In my .Net6 web app, I attempted to register service injection for 2 implementations of a single IWordRepository Interface:
WordRepositoryInMemory, working with in-memory data;WordRepositoryDatabasewith 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?