UserManager 不在单元测试中创建用户
UserManager not creating users in Unit Tests
我正在使用 xUnit 和 Moq,我想要实现的通常是创建身份用户,因此它存储在 Entity Framework 内存数据库中。
我已经建立了种子数据功能 - 它会在我的 ASP.NET 核心主机应用程序启动并完美运行时触发 - 所以没问题。
但是当我使用模拟的 UserManager 时会出现问题。没有抛出异常,只是没有保存用户。
在调试测试时验证,DbContext
returns 0 个用户,同时 UserManager.FindByNameAsync
产生 null
。
不知道是什么原因。可能是因为我 assemble UserManager 在 SeedDataTest
class 的构造函数中的方式?
public class SeedDataTest
{
private AppDbContext dbContext;
private UserManager<ApplicationUser> userManager;
private ITenantService tenantService;
public SeedDataTest()
{
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase(databaseName: "in_memory_db")
.Options;
dbContext = new AppDbContext(options);
var userStore = new UserStore<ApplicationUser>(dbContext);
userManager = new Mock<UserManager<ApplicationUser>>(
userStore,
new Mock<IOptions<IdentityOptions>>().Object,
new Mock<IPasswordHasher<ApplicationUser>>().Object,
new IUserValidator<ApplicationUser>[0],
new IPasswordValidator<ApplicationUser>[0],
new Mock<ILookupNormalizer>().Object,
new Mock<IdentityErrorDescriber>().Object,
new Mock<IServiceProvider>().Object,
new Mock<ILogger<UserManager<ApplicationUser>>>().Object)
.Object;
tenantService = new Mock<TenantService>(dbContext).Object;
}
[Fact]
public void Test1()
{
new TenantsCreator(dbContext).Create();
new UserCreator(dbContext, tenantService, userManager).Create(); // stuck here
new MembershipCreator(dbContext, userManager).Create();
// unfinished
}
}
这是来自 UserCreator
的代码
public class UserCreator
{
private AppDbContext _context;
private ITenantService _tenantService;
private UserManager<ApplicationUser> _userManager;
public UserCreator(
AppDbContext context,
ITenantService tenantService,
UserManager<ApplicationUser> userManager
)
{
_context = context;
_tenantService = tenantService;
_userManager = userManager;
}
public void Create()
{
Task.Run(async () => await CreateUsers()).ConfigureAwait(false).GetAwaiter().GetResult();
}
private async Task CreateUsers()
{
ApplicationUser hostAdminUser = _context.Users.FirstOrDefault(x => x.UserName.Equals(SetupConsts.Users.AdminJoe.UserName));
if (hostAdminUser == null)
{
hostAdminUser = new ApplicationUser()
{
FirstName = SetupConsts.Users.AdminJoe.FirstName,
LastName = SetupConsts.Users.AdminJoe.LastName,
UserName = SetupConsts.Users.AdminJoe.UserName,
Email = SetupConsts.Users.AdminJoe.Email,
EmailConfirmed = true,
PasswordHash = new PasswordHasher<ApplicationUser>().HashPassword(hostAdminUser, SetupConsts.Users.Passwords.Default)
};
await _userManager.CreateAsync(hostAdminUser);
}
ApplicationUser secondaryUser = _context.Users.FirstOrDefault(x => x.UserName.Equals(SetupConsts.Users.JohnRoe.UserName));
if (secondaryUser == null)
{
secondaryUser = new ApplicationUser()
{
FirstName = SetupConsts.Users.JohnRoe.FirstName,
LastName = SetupConsts.Users.JohnRoe.LastName,
UserName = SetupConsts.Users.JohnRoe.UserName,
Email = SetupConsts.Users.JohnRoe.Email,
EmailConfirmed = true,
PasswordHash = new PasswordHasher<ApplicationUser>().HashPassword(secondaryUser, SetupConsts.Users.Passwords.Default)
};
await _userManager.CreateAsync(secondaryUser);
}
}
}
我们使用模拟框架来允许我们构建模拟(替代)依赖项以及指定从我们的 SUT 中使用的 classes/interfces 返回的内容。
数据库本身就是一个很好的用例。在测试对象时,我们总是想知道对象的确切状态,唯一的方法就是自己表达对象的内容。
这就是 Moq 的用武之地。其功能之一是允许我们声明方法调用的结果。
我相信您看到返回的结果为 0,因为您使用的是 class 的最小起订量实现(实际上并未调用已实现的 class)。为了获得结果,您需要进行一些设置:
mockedClass.Setup(x => x.GetUserDetails(It.IsAny<int>())).Returns(new UserDetails());
要么这样做,要么确保您传递的是 UserManager class 的具体实现,而不是模拟版本:
userManager = new UserManager<ApplicationUser>
希望对您有所帮助
我正在使用 xUnit 和 Moq,我想要实现的通常是创建身份用户,因此它存储在 Entity Framework 内存数据库中。
我已经建立了种子数据功能 - 它会在我的 ASP.NET 核心主机应用程序启动并完美运行时触发 - 所以没问题。
但是当我使用模拟的 UserManager 时会出现问题。没有抛出异常,只是没有保存用户。
在调试测试时验证,DbContext
returns 0 个用户,同时 UserManager.FindByNameAsync
产生 null
。
不知道是什么原因。可能是因为我 assemble UserManager 在 SeedDataTest
class 的构造函数中的方式?
public class SeedDataTest
{
private AppDbContext dbContext;
private UserManager<ApplicationUser> userManager;
private ITenantService tenantService;
public SeedDataTest()
{
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase(databaseName: "in_memory_db")
.Options;
dbContext = new AppDbContext(options);
var userStore = new UserStore<ApplicationUser>(dbContext);
userManager = new Mock<UserManager<ApplicationUser>>(
userStore,
new Mock<IOptions<IdentityOptions>>().Object,
new Mock<IPasswordHasher<ApplicationUser>>().Object,
new IUserValidator<ApplicationUser>[0],
new IPasswordValidator<ApplicationUser>[0],
new Mock<ILookupNormalizer>().Object,
new Mock<IdentityErrorDescriber>().Object,
new Mock<IServiceProvider>().Object,
new Mock<ILogger<UserManager<ApplicationUser>>>().Object)
.Object;
tenantService = new Mock<TenantService>(dbContext).Object;
}
[Fact]
public void Test1()
{
new TenantsCreator(dbContext).Create();
new UserCreator(dbContext, tenantService, userManager).Create(); // stuck here
new MembershipCreator(dbContext, userManager).Create();
// unfinished
}
}
这是来自 UserCreator
public class UserCreator
{
private AppDbContext _context;
private ITenantService _tenantService;
private UserManager<ApplicationUser> _userManager;
public UserCreator(
AppDbContext context,
ITenantService tenantService,
UserManager<ApplicationUser> userManager
)
{
_context = context;
_tenantService = tenantService;
_userManager = userManager;
}
public void Create()
{
Task.Run(async () => await CreateUsers()).ConfigureAwait(false).GetAwaiter().GetResult();
}
private async Task CreateUsers()
{
ApplicationUser hostAdminUser = _context.Users.FirstOrDefault(x => x.UserName.Equals(SetupConsts.Users.AdminJoe.UserName));
if (hostAdminUser == null)
{
hostAdminUser = new ApplicationUser()
{
FirstName = SetupConsts.Users.AdminJoe.FirstName,
LastName = SetupConsts.Users.AdminJoe.LastName,
UserName = SetupConsts.Users.AdminJoe.UserName,
Email = SetupConsts.Users.AdminJoe.Email,
EmailConfirmed = true,
PasswordHash = new PasswordHasher<ApplicationUser>().HashPassword(hostAdminUser, SetupConsts.Users.Passwords.Default)
};
await _userManager.CreateAsync(hostAdminUser);
}
ApplicationUser secondaryUser = _context.Users.FirstOrDefault(x => x.UserName.Equals(SetupConsts.Users.JohnRoe.UserName));
if (secondaryUser == null)
{
secondaryUser = new ApplicationUser()
{
FirstName = SetupConsts.Users.JohnRoe.FirstName,
LastName = SetupConsts.Users.JohnRoe.LastName,
UserName = SetupConsts.Users.JohnRoe.UserName,
Email = SetupConsts.Users.JohnRoe.Email,
EmailConfirmed = true,
PasswordHash = new PasswordHasher<ApplicationUser>().HashPassword(secondaryUser, SetupConsts.Users.Passwords.Default)
};
await _userManager.CreateAsync(secondaryUser);
}
}
}
我们使用模拟框架来允许我们构建模拟(替代)依赖项以及指定从我们的 SUT 中使用的 classes/interfces 返回的内容。
数据库本身就是一个很好的用例。在测试对象时,我们总是想知道对象的确切状态,唯一的方法就是自己表达对象的内容。
这就是 Moq 的用武之地。其功能之一是允许我们声明方法调用的结果。
我相信您看到返回的结果为 0,因为您使用的是 class 的最小起订量实现(实际上并未调用已实现的 class)。为了获得结果,您需要进行一些设置:
mockedClass.Setup(x => x.GetUserDetails(It.IsAny<int>())).Returns(new UserDetails());
要么这样做,要么确保您传递的是 UserManager class 的具体实现,而不是模拟版本:
userManager = new UserManager<ApplicationUser>
希望对您有所帮助