1

I'm developing an application with .NET Core and EF. I'm trying to implement some unit test using FakeItEasy and NUnit. Here's my problem. I've a DbContext as this one:

public class PostgresDbContext : IdentityDbContext<User, IdentityRole<int>, int> {
    // Add DbSets
    public virtual DbSet<Institution> Institutions { get; set; }

    public virtual DbSet<Employee> Employees { get; set; }
...

Then I've a repository that uses PostgresDbContext:

    public class UserRepository {
    private readonly PostgresDbContext _dbContext;

    public UserRepository(PostgresDbContext dbContext) {
        _dbContext = dbContext;
    }
    ...

And finally I've a service (the class that I'm trying to test) which uses UserRepository.

    public class AuthService : BaseServiceAbstract {
    private readonly SignInManager<User> _signInManager;
    private readonly UserRepository _userRepository;

    public AuthService(SignInManager<User> signInManager, UserRepository userRepository) {
        _signInManager = signInManager;
        _userRepository = userRepository;
    }

The problem is when I try to Mock UserRepository in the following method:

    [Test, Description("Should login when provided with right credentials")]
    public void Login() {
        var user = new Employee {Name = "user"};
        var signInManger = A.Fake<SignInManager<User>>();
        var userRepository = A.Fake<UserRepository>();

        _authService = new AuthService(signInManger, userRepository);

        A.CallTo(() => userRepository.FindUserByUsername("user"))
            .Returns(user);
        
        _authService.Login("user", "password");
    }

I throws me the error:

FakeItEasy.Core.FakeCreationException : 
Failed to create fake of type DAL.Repositories.UserRepository:

The constructors with the following signatures were not tried:
(*DAL.PostgresDbContext)

Types marked with * could not be resolved. Please provide a Dummy Factory to enable these constructors.

Any idea?

Miguel Andrade
  • 346
  • 3
  • 13
  • 1
    For some reason FakeItEasy can't construct a `PostgresDbContext`. The class is public, which is good, but FakeItEasy can't find a public constructor. Seeing the rest of the class might shed some light. Provide the source if you can. But this sort of thing can crop up when faking concrete types. I'd avoid the problem by faking an `IUserRepository` interface extracted from `UserRepository` if you can. Interfaces fake easier and are more predictable than classes. – Blair Conrad Feb 08 '22 at 00:16
  • 1
    Yeah, OP, you have the right idea, mocking the repository, but you should be using a contract Interface for your repository (IUserRepository) which exposes your methods. The concrete class may have dependencies like the DbContext but relying on the interface for dependencies rather than concrete instances means those dependencies can be mocked properly without needing to worry about dependency chains. – Steve Py Feb 08 '22 at 04:28

1 Answers1

4

To create a fake UserRepository, FakeItEasy needs an instance of PostgresDbContext. So it tries to create a fake one, but doesn't succeed (I don't have enough details to determine why exactly). Anyway, mocking a DbContext is always difficult.

Instead of mocking UserRepository directly, consider introducing a IUserRepository interface, implemented by UserRepository, and inject that in your AuthService. Mocking interfaces is generally much easier than mocking classes.

In general, you should avoid making your classes depend on other concrete classes. They should depend on abstractions instead. This will make your life much easier when writing unit tests.

Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758