如何模拟自定义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实体
我曾多次尝试用不同的框架和方法模拟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();
我的单元测试运行良好!