使用Identity的管理器在由UseInMemoryDatabase()创建的IdentityDbContext中

3
我设计了这个方法,让单元测试 DbContext 更加简单。这个方法将我的dbContext 存储在内存中。我用实体(例如,在单元测试中使用类似于 _context.Projects, _context.Tests 等)测试它,这个方法有效。
        public static TaskManagerDbContext Create()
        {
            var options = new DbContextOptionsBuilder<TaskManagerDbContext>()
                                .UseInMemoryDatabase(Guid.NewGuid().ToString())
                                .EnableSensitiveDataLogging(true)
                                .Options;

            var context = new TaskManagerDbContext(options);
            context.SaveChanges();

            return context;
        }

我的DbContextClass如下所示:


    public class TaskManagerDbContext : IdentityDbContext<ApplicationUser>, ITaskManagerDbContext
    {
        public TaskManagerDbContext(DbContextOptions<TaskManagerDbContext> options)
            : base(options)
        {
        }

        //db sets here

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.ApplyConfigurationsFromAssembly(typeof(TaskManagerDbContext).Assembly);
        }
    }

我的问题是,我们能否像使用IdentityDbContext一样,将Identity的UserManagerSignInManagerRoleManager存储在内存中?如何在内存中对用户、角色等Identity内容进行单元测试,就像我们可以使用标准的Context一样?如何在存储在内存中的虚拟上下文中调用这些Managers
编辑:根据这个SO问题,很明显,Identity共享上下文context。但是如何在UseInMemoryDatabase()方法创建的IdentityDbContext中使用Managers呢?
编辑2:我正在通过夹具注入context
public class DatabaseFixture
{
    public TaskManagerDbContext Context { get; private set; }

    public DatabaseFixture()
    {
        this.Context = DatabaseContextFactory.Create();
    }
}

[CollectionDefinition("DatabaseTestCollection")]
public class QueryCollection : ICollectionFixture<DatabaseFixture>
{
}

并且它的使用:

[Collection("DatabaseTestCollection")]
public class RegisterUserCommandTests
{
    private readonly TaskManagerDbContext _context;

    public RegisterUserCommandTests(DatabaseFixture fixture)
    {
        _context = fixture.Create();
    }

    //and usage of it in class:
    var user = _context.Projects.Find(8);
}

我正在使用Xunit

1个回答

5
您需要创建服务集合,将所有内容注册到其中,然后使用它来提取所需内容。
var services = new ServiceCollection();
services.AddDbContext<TaskManagerDbContext>(o =>
    o.UseInMemoryDatabase(Guid.NewGuid()));
services.AddIdentity<IdentityUser, IdentityRole>()
    .AddEntityFrameworkStores<TaskManagerDbContext>();
var provider = services.BuildServiceProvider();

接下来,您可以使用provider

using (var scope = provider.CreateScope())
{
    var userManager = scope.ServiceProvider.GetRequiredService<UserManager<IdentityUser>>();
}

那么,我能够在我的InMemory数据库上使用相关的Managers吗?我可以在我的Fixture类中实现它吗? - michasaucer
1
是的,没错。你只需要关注作用域。如果所有内容都在同一作用域内,你就只能与经理们使用相同的上下文。出于这个原因,你也不能像在fixture中那样持久化你的上下文。相反,暴露provider,然后使用我上面所做的方法,在CreateScope中包装你的测试。 - Chris Pratt
我相信你的答案是可行的。如果我遇到问题,我会在这里评论。 - michasaucer
我需要在每个测试方法中使用 using (var scope = provider.CreateScope()) 吗?如果不需要,你能告诉我如何在这个作用域中模拟用户以在所有测试 class 中使用吗? - michasaucer
是的,至少在你需要这些作用域服务的情况下是这样。对于“共享”用户,存储原始数据,然后将其作为每个测试的一部分添加到上下文中。无论如何,您几乎都需要这样做,因为您不希望测试数据在测试之间泄漏。 - Chris Pratt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接