如何模拟自定义UserStore和RoleStore

本文关键字:自定义 UserStore RoleStore 模拟 何模拟 | 更新日期: 2023-09-27 18:13:10

我使用的是ASP。使用自定义UserStore和RoleStore进行标识。
这是我的数据库上下文:

public class AppDbContext 
  : IdentityDbContext<User, Role, int, UserLogin, UserRole, UserClaim>

在我的Seed方法中有以下代码来添加用户:

// UserManager
var userStore = new UserStore<User, Role, int, UserLogin, UserRole, UserClaim>(context)
var userManager = new UserManager<User, int>(userStore);
// RoleManager
var roleStore = new RoleStore<Role, int, UserRole>(context)
var roleManager = new RoleManager<Role, int>(roleStore);
// Create Roles
roleManager.Create(new Role(roleName));
...
// Create Users
var user = new User { ... };
var result = userManager.Create(user, password);
...
// Add Users to Roles
userManager.AddToRole(user.Id, roleName);
...

如何在我的单元测试中使用Mock框架?

我需要为以下方法编写单元测试:

public IEnumerable<User> GetUsersInRole(string roleName)
{
    return (from u in this.DbContext.Users
        from ur in u.Roles
        join r in this.DbContext.Roles on ur.RoleId equals r.Id
        where r.Name == roleName
        select u).Distinct();
}

这是我的测试方法:

this.Bind<Mock<AppDbContext>>()
    .ToMethod(
        m =>
        NunitTestHelper.GetDbContextMock()
            //.SetupDbContextData(x => x.Roles, this.RolesCollection.AsQueryable())
            //.SetupDbContextData(x => x.Users, this.UsersCollection.AsQueryable())
            ).InTransientScope();
var context = this.Kernel.Get<AppDbContext>();
var userStore = new Mock<UserStore<User, Role, int, UserLogin, UserRole, UserClaim>>(context);
var userManager = new UserManager<User, int>(userStore.Object);
var roleStore = new Mock<RoleStore<Role, int, UserRole>>(context);
var roleManager = new RoleManager<Role, int>(roleStore.Object);
roleManager.Create(new Role(roleName));
for (var i = 0; i < num; i++)
{
    var id = i + 1;
    var user = new User { Id = id,  UserName = "User" + i };
    var result = userManager.Create(user);
    userManager.AddToRole(id, roleName); // Exception
}

在线"userManager. net "AddToRole"我得到以下异常:

"UserId not found."

如何将用户添加到单元测试中的角色?
我不能直接访问UserRoles实体

如何模拟自定义UserStore和RoleStore

我曾多次尝试用不同的框架和方法模拟DbContext。我从来没有得到一个可靠的模拟对象,它在各种情况下都表现得和真实对象一样。

或者当我可以模拟DbContext时,设置代码非常庞大,很难设置,不值得。此外,这种设置非常脆弱,每次更改实际代码都会崩溃。

测试数据库相关代码的最佳方法是使用实际的数据库。这样的测试不再是单元测试,而是集成测试。但这是一个术语——你仍然在测试你的代码(和数据库结构)。

不幸的是,设置可靠运行的数据库测试需要更多的努力。但如果你想深入了解,这里有一些参考资料:

  • 我写过我的方法。
  • 我的方法是基于Jimmy Bogard的文章:1和2
  • 这里是Jimmy关于DB测试的最新系列文章:系列和关于Respawn的单独文章

谢谢!我已经找到了解决方案,但我不确定这是否是一个好方法。

所以,我已经实现了我的测试用户:

public class TestUser : User
{
    private List<UserRole> roles;
    public TestUser()
    {
        this.roles = new List<UserRole>();
    }
    public override ICollection<UserRole> Roles
    {
        get
        {
            return this.roles;
        }
    }
    public TestUser AddRole(Role role)
    {
        this.roles.Add(new UserRole { RoleId = role.Id, UserId = this.Id });
        return this;
    }
}

在我的单元测试设置:

// Private Members
private List<Role> rolesCollection;
private List<TestUser> usersCollection;
// Public Properties
public IList<Role> RolesCollection
{
    get
    {
        return this.rolesCollection ?? (this.rolesCollection = new List<Role>(NunitTestDataHelper.GetRoles()));
    }
}
public IList<TestUser> UsersCollection
{
    get
    {
        return this.usersCollection
               ?? (this.usersCollection =
                   new List<TestUser>(
                       new[]
                       {
                           new TestUser { Id = 1, UserName = "Usr1" }.AddRole(this.RolesCollection[0]).AddRole(this.rolesCollection[1]), 
                           new TestUser { Id = 2, UserName = "Usr2" }.AddRole(this.RolesCollection[0]),
                           new TestUser { Id = 3, UserName = "User1" }.AddRole(this.rolesCollection[1]),
                           new TestUser { Id = 4, UserName = "User2" },
                            ...
                       }));
    }
}
// Setup DB
this.Bind<Mock<AppDbContext>>()
    .ToMethod(
        m =>
        NunitTestHelper.GetDbContextMock()
            .SetupDbContextData(x => x.Roles, this.RolesCollection.AsQueryable())
            .SetupDbContextData(x => x.Users, this.UsersCollection.AsQueryable()))
            .InTransientScope();

我的单元测试运行良好!