I am trying to create a Mock (using Moq) for an IServiceProvider
so that I can test my repository class:
public class ApiResourceRepository : IApiRe
I'd like to argue that when you need to add that much ceremony just to mock a simple method, then maybe your code isn't very testable. So another option would be to hide the service locator behind a more test and mock friendly interface (and in my opinion a nicer one too):
public interface IServiceLocator : IDisposable
{
T Get();
}
public class ScopedServiceLocator : IServiceLocator
{
private readonly IServiceScopeFactory _factory;
private IServiceScope _scope;
public ScopedServiceLocator(IServiceScopeFactory factory)
{
_factory = factory;
}
public T Get()
{
if (_scope == null)
_scope = _factory.CreateScope();
return _scope.ServiceProvider.GetService();
}
public void Dispose()
{
_scope?.Dispose();
_scope = null;
}
}
I've only implemented the GetService
method here, but you could easily add/remove so that the locator better suites your need.
And an example of how to use it;
public class ALongRunningTask : IRunForALongTime
{
private readonly IServiceLocator _serviceLocator;
public ALongRunningTask(IServiceLocator serviceLocator)
{
_serviceLocator = serviceLocator;
}
public void Run()
{
using (_serviceLocator)
{
var repository = _serviceLocator.Get();
}
}
}