Is there a good way of injecting mocked repositories using .NET DI framework?

I have the following generic repository:

public interface IRepository<T> where T : BaseEntity
{
    IMongoQueryable Entities { get; }
    Task<T> AddAsync(T entity, InsertOneOptions? options, CancellationToken cancellationToken = default);
    //...
}

By using .NET DI approach, I can inject dynamically my repository to my container and use it around with easiness:

serviceCollection.AddScoped(typeof(Repository<>), typeof(IRepository<>));

That works beautifully.
However, I’m trying to find a nice approach to use mocked repositories in my test cases.
For instance, I have a service provider on my test scenarios where I can benefit of my dependency injection for getting instances of objects. e.g.:

public class UserService : IUserService
{
    private IMapper _mapper;
    private IRepository<UserEntity> _userRepository;
    private ValidatorService<UserInput> _userInputValidator;

    public UserService(IMapper mapper, IRepository<UserEntity> userRepository, ValidatorService<UserInput> userInputValidator)
    {
        (_mapper, _userRepository, _userInputValidator) = (mapper, userRepository, userInputValidator);
    }
}

//...
_userService = ServiceProvider.GetRequiredService<UserService>();

That works as well, I get a proper instance of my service class and can test it.
But then, on my test cases, I would like to avoid doing that every time:

_mapper = ServiceProvider.GetRequiredService<IMapper>();
// \/ here
_userRepositoryMock = new Mock<IRepository<UserEntity>>();
_userInputValidator = ServiceProvider.GetRequiredService<ValidatorService<UserInput>>();

_userService = new UserService(_mapper, _userRepositoryMock.Object, _userInputValidator);

Instead of creating my mock manually, I’d like to use DI to scope the mocked repository and, whenever I request my userService from a specific container, I get the mocked version and not the “original” implementation”. Something like:

serviceCollection.AddScoped(typeof(IRepository<>), new Mock<Repository<>>());

Do you made it already/know how to/believe this is possible do achieve?

  • 2

    You could build a ServiceCollection object with mocked implementations. You would just do what you do in your real application, pretty much, but with mocks. However, this is not advisable because most often than not, one needs to set a mock up in a different way for different tests. Having a DI container in your tests would, in my opinion, make unit testing more difficult.

    – 

What you are asking for is an Auto-mocking Container, but that said, you shouldn’t need a DI Container for unit testing.

On the other hand, overriding how an entire application is composed can be useful for more coarse-grained tests (e.g. integration tests). Here’s an example of how to do that for ASP.NET applications. In such cases, however, I would recommend favouring state-based testing over interaction-based testing, so use Fake Objects rather than dynamic mock libraries.

Leave a Comment