如何模拟自定义UserStore和RoleStore

时间:2015-09-16 13:19:42

标签: c# unit-testing mocking asp.net-identity

我在自定义UserStore和RoleStore中使用ASP.Identity 这是我的数据库上下文:

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
}

在线&#34; userManager.AddToRole&#34;我得到以下异常:

&#34;未找到UserId。&#34;

如何在单元测试中将用户添加到角色?
我无法直接访问UserRoles实体。

2 个答案:

答案 0 :(得分:1)

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

或者当我可以模拟DbContext时,设置代码非常庞大且难以设置,这是不值得的。此外,该设置非常脆弱,并且在实际代码的每次更改时都会出现问题。

测试与数据库相关的代码的最佳方法是转到实际的数据库。这些测试不再是单元测试,而是成为集成测试。但这是一个术语 - 您仍在测试代码(和数据库结构)。

不幸的是,设置可靠运行的数据库测试需要花费更多的精力。但是如果你想看看这个,这里有一些参考:

答案 1 :(得分:0)

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

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

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

我的单元测试运行良好!