【问题标题】:Asp .Net Core Unit Test Mock UserManager.CreateAsync and return Identity ResultAsp .Net 核心单元测试模拟 UserManager.CreateAsync 并返回身份结果
【发布时间】:2019-12-18 07:34:46
【问题描述】:

从事 .Net Core 项目并创建以下服务以跨页面共享通用方法。

namespace MyApp.Tests.Services
{
    public class UserServiceTest
    {
        [Fact]
        public async Task CreateUser_ShouldCreateUser()
        {
            var user = new UserResponse
            {
                Id = "111",
                Email = "john@email.com",
                FirstName = "John",
                LastName = "Doe",
                CompanyName = "SomeCompany",
                PhoneNumber = "9123456789"
            };

            var appUser = new ApplicationUser
            {
                UserName = user.Email,
                Email = user.Email,
                FirstName = user.FirstName,
                LastName = user.LastName,
                CompanyName = user.CompanyName,
                PhoneNumber = user.PhoneNumber
            };

            var logger = Mock.Of<ILogger<UserService>>();
            var mockUserStore = new Mock<IUserStore<ApplicationUser>>();
            mockUserStore
                .Setup(x => x.CreateAsync(appUser, CancellationToken.None))
                .ReturnsAsync(IdentityResult.Success).Verifiable();

            // Tried this one as well but still getting null instead of IdentityResult
            // mockUserStore
            //     .Setup(x => x.CreateAsync(appUser, CancellationToken.None))
            //     .ReturnsAsync(new IdentityResultMock(true));

            var userManager = new UserManager<ApplicationUser>(mockUserStore.Object, null, null, null, null, null, null, null, null);
            var _userService = new UserService(userManager, logger);

            var result = await _userService.CreateUserInApp(user);

            Assert.True(result.Succeeded);
        }
    }

    public class IdentityResultMock : IdentityResult
    {
        public IdentityResultMock(bool succeeded) {
            base.Succeeded = succeeded;
         }
    }
}

还为此服务编写了单元测试用例,如下所示来测试 UserService

namespace MyApp.Tests.Services
{
    public class UserServiceTest
    {
        [Fact]
        public async Task CreateUser_ShouldCreateUser()
        {
            var user = new UserResponse
            {
                Id = "111",
                Email = "john@email.com",
                FirstName = "John",
                LastName = "Doe",
                CompanyName = "SomeCompany",
                PhoneNumber = "9123456789"
            };

            var appUser = new ApplicationUser
            {
                UserName = user.Email,
                Email = user.Email,
                FirstName = user.FirstName,
                LastName = user.LastName,
                CompanyName = user.CompanyName,
                PhoneNumber = user.PhoneNumber
            };

            var logger = Mock.Of<ILogger<UserService>>();
            var mockUserStore = new Mock<IUserStore<ApplicationUser>>();
            mockUserStore
                .Setup(x => x.CreateAsync(appUser, CancellationToken.None))
                .ReturnsAsync(IdentityResult.Success).Verifiable(); ;

            var userManager = new UserManager<ApplicationUser>(mockUserStore.Object, null, null, null, null, null, null, null, null);
            var _userService = new UserService(userManager, logger);

            var result = await _userService.CreateUserInApp(user);

            Assert.True(result.Succeeded);
        }
    }
}

在用户服务中运行测试时

var createResult = await _userManager.CreateAsync(appUser);

createResult 由于此测试用例失败并出现空引用异常,我得到空值。 如果我可以从模拟 CreateAsync 设置返回 IdentityResult,那么它将通过但不确定我在做什么错。 也无法创建 IdentityResult 的对象,因为“成功”受保护并且无法显式分配值。 请帮忙。谢谢:)

【问题讨论】:

    标签: c# asp.net asp.net-core asp.net-identity xunit.net


    【解决方案1】:

    我们需要看看构造函数内部发生了什么:

    var userManager = new UserManager<ApplicationUser>(mockUserStore.Object, null, null, null, null, null, null, null, null);
    

    但不是真的。如果你在这里测试UserService,那么你应该嘲笑的是UserManager,而不是它的内部依赖IUserStore

    这是为什么呢?因为UserManager 的内部结构可能会发生变化,然后您必须同时更改UserManager 测试和UserService 测试。

    模拟 UserManager 的创建,就像对 IUserStore 所做的那样,您会发现它是 UserStore 中的其他一些依赖项,或者完全超出了单元测试范围的某个地方。

    编辑 1

    我想我发现了你的问题:

    mockUserStore
        .Setup(x => x.CreateAsync(appUser, CancellationToken.None))
        .ReturnsAsync(IdentityResult.Success).Verifiable();
    

    和调用

    var result = await _userService.CreateUserInApp(user);
    

    User 对象和 appUser 对象不一样,所以 mocking 框架没有返回预期值。

    要确保这是问题所在,请尝试使用模拟

    mockUserStore
        .Setup(x => x.CreateAsync(It.IsAny<ApplicationUser>(), It.IsAny<CancellationToken>()))
        .ReturnsAsync(IdentityResult.Success).Verifiable();
    

    【讨论】:

    • 我可以像 stackoverflow.com/questions/49165810/… 这样模拟 userManager,但它不会解决返回 IdentityResult 的主要问题。
    • 检查更新的答案。它可能会解决您的问题。
    • 它有效:)。一个请求 - 您能否更新您的答案(更新的方法名称为 CreateUserInApp)。这样我就可以将其标记为已接受的答案。
    猜你喜欢
    • 1970-01-01
    • 2017-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多