简体   繁体   中英

Dependency injecting an ASP.NET Identity user (and unit testing)

I don't fully understand how to refactor my app to make it more testable.

I am using ASP.NET Core 3.0 (Razor Pages, if that matters).

Current State:

I have razor pages models that inject in my context (inherited from IdentityDbContext) and userManager:

public class DashboardModel : PageModel
{

    private readonly ApplicationDbContext _context;
    private readonly UserManager<AVUser> _userManager;

    public DashboardModel(ApplicationDbContext context, UserManager<AVUser> userManager)
    {
        _context = context;
        _userManager = userManager;
    }
    public async Task<IActionResult> OnGetAsync()
    {
        AVUser = await _userManager.GetUserAsync(User);
        MyRepository myRepository = new MyRepository(_context, AVUser);

        // omitted - just getting data from the repository for use on the page

        return Page();
    }

I have repositories created who have constructors as the following:

public MyRepository(ApplicationDbContext context, AVUser user) 

I never use the context directly in my Model classes and instead create repositories in the Model classes using the context passed in. In this case ApplicationDbContext is my EF Core context, and AVUser is my type of Identity User, defined as:

public class AVUser : IdentityUser

My DI is set up as:

// DB Setup
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));


// Identity Setup
        services.AddDefaultIdentity<AVUser>(config =>
        {
            config.SignIn.RequireConfirmedEmail = true; 
        })
        .AddEntityFrameworkStores<ApplicationDbContext>();

What I don't understand

I want to make my razor pages model classes unit testable without relying on the database or repository classes, mocking up the repository class, so I expect I have to remove the context from the constructor and instead created interfaces for my repositories and DI them.

However, I don't know how to DI in the user parameter for the Repository - how do I set up my service in Startup.cs so this can get passed in? Today to get the value for this, I run:

AVUser = await _userManager.GetUserAsync(User);

If you inject your repositories in the DI container, IoC will automatically inject their dependencies like controllers and pages. so you just need to have a constructor like this in your repository class:

private readonly ApplicationDbContext _context;
private readonly UserManager<AVUser> _userManager;

public MyRepository(ApplicationDbContext context, UserManager<AVUser> userManager)
{
    _context = context;
    _userManager = userManager;
}

and then inject it to the container:

services.AddTransient<IMyRepository,MyRepository>();

and that's it. remember to create an interface for your repository so you can inject different instances for either production or testing. Nonetheless, You shouldn't rely on DI for testing. If you are writing unit tests then create a test implementation for your MyRepository and simply instantiate it. If you are writing integration tests then you have to use a different sturtup class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM