【问题标题】:UserManager not creating users in Unit TestsUserManager 不在单元测试中创建用户
【发布时间】:2019-03-22 06:03:30
【问题描述】:

我正在使用 xUnit 和 Moq,我想要实现的通常是创建身份用户,以便将其存储在 Entity Framework In-Memory DB 中。

我已经建立了种子数据功能 - 当我的 ASP.NET Core 主机应用程序启动并完美运行时它会被触发 - 所以没问题。

但是当我使用模拟的 UserManager 时会出现问题。没有抛出异常,只是没有保存用户。

在调试测试时验证,DbContext 返回 0 个用户,UserManager.FindByNameAsync 也产生 null

不知道是什么原因。难道是因为我在SeedDataTest类的构造函数中组装UserManager的方式?

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

【问题讨论】:

    标签: unit-testing asp.net-core asp.net-identity moq xunit


    【解决方案1】:

    我们使用模拟框架来允许我们构建模拟(替换)依赖项,并指定从 SUT 中使用的类/接口返回的内容。

    一个很好的用例是数据库本身。在测试对象时,我们总是想知道对象的确切状态,而我们做到这一点的唯一方法就是自己表达它们的内容。

    这就是 Moq 的用武之地。它的功能之一是允许我们声明方法调用的结果。

    我相信您看到返回的结果为 0,因为您使用的是类的 moq 实现(实际上并没有调用实现的类)。为了获得结果,您需要进行一些设置:

    mockedClass.Setup(x => x.GetUserDetails(It.IsAny<int>())).Returns(new UserDetails());
    

    要么这样做,要么确保您传递的是 UserManager 类的具体实现,而不是模拟版本:

     userManager = new UserManager<ApplicationUser>
    

    希望有帮助

    【讨论】:

    • 需要一个具体的实现——绝对是这样,真的非常感谢!
    猜你喜欢
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多