简体   繁体   English

如何模拟自定义 UserStore 和 RoleStore

[英]How to mock custom UserStore and RoleStore

I am using ASP.Identity with custom UserStore and RoleStore.我将 ASP.Identity 与自定义 UserStore 和 RoleStore 一起使用。
This is my DB context:这是我的数据库上下文:

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

I have the following code in my Seed method to add users:我的 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);
...

How to do it in my unit tests with Mock framework?如何使用 Mock 框架在我的单元测试中做到这一点?

I need to write the unit test for the following method:我需要为以下方法编写单元测试:

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 is the piece of my test method:这是我的测试方法的一部分:

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
}

On line "userManager.AddToRole" I get the following exception:在线“userManager.AddToRole”我得到以下异常:

"UserId not found." “未找到用户 ID。”

How to add users to roles in unit tests?如何在单元测试中将用户添加到角色?
I don't have directly access to the UserRoles entity.我没有直接访问 UserRoles 实体的权限。

I have tried to mock DbContext multiple times with different frameworks and approaches.我曾尝试使用不同的框架和方法多次模拟DbContext And never I could get a reliable mock object that behaved just like the real one in all kind of situation.我从来没有得到一个可靠的模拟对象,它在各种情况下都表现得像真实的一样。

Or when I could simulate the DbContext , the set up code was so massive and so hard to set up, it was not worth it.或者当我可以模拟DbContext ,设置代码如此庞大且难以设置,不值得。 Also that set up was incredibly brittle and broke on every single change of the actual code.此外,该设置非常脆弱,并且在实际代码的每一次更改时都会中断。

The best approach to test database-related code is to go to an actual database.测试与数据库相关的代码的最佳方法是访问实际数据库。 Such tests stop being unit tests and become integration tests.这样的测试不再是单元测试而成为集成测试。 But this is a terminology - you are still testing your code (and the database structure).但这是一个术语——您仍在测试您的代码(和数据库结构)。

Unfortunately it takes a bit more effort to set up database tests that run reliably.不幸的是,设置可靠运行的数据库测试需要更多的努力。 But if you desire to look into this, here are some references:但是如果你想研究这个,这里有一些参考:

Thanks!谢谢! I have found solution but I am not sure if it is a good approach.我找到了解决方案,但我不确定这是否是一个好方法。

So, I've implemented my test user:所以,我已经实现了我的测试用户:

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;
    }
}

In my unit test setup:在我的单元测试设置中:

// 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();

My unit tests work well!我的单元测试运行良好!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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