如何模拟UserManager <identityuser>

时间:2019-03-29 07:52:41

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

我正在尝试找出如何在我的项目中添加单元测试。我认为最好是从一个空白项目开始,然后从头开始进行设计,而不是将其添加到我的主项目中。一旦了解了流程,我就可以开始重构我的项目以添加测试。

网络应用程序

因此,我创建了一个Web应用程序,并向其中添加了默认用户身份。

这给了我一个像这样的启动

public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });

        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>()
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

然后我创建了一个简单的控制器,并在构造函数中传递了usermanager。

[Route("api/[controller]")]
[ApiController]
public class SweetController : ControllerBase
{
    private readonly UserManager<IdentityUser> _userManager;

    public SweetController(UserManager<IdentityUser> userManager)
    {
        _userManager = userManager;
    }
    public async Task<int> NumberOfGummyBearsForUser(string userId)
    {
        var user = await _userManager.FindByIdAsync(userId);
        var userHasASweetTooth = await _userManager.IsInRoleAsync(user, "SweetTooth");
        if (userHasASweetTooth)
        {
            return 100;
        }
        else
        {
            return 1;
        }
    }
}

单元测试

我一直想做的第一件事就是模拟该用户管理器,但是它不起作用。

public void Test1()
    {
        // Arrange
        var mockUser = new Mock<UserManager<IdentityUser>>();
        var userManager = new UserManager(mockRepo.Object);  <-- error here see image below

        var controller = new SweetController(userManager.Object);

        // Act
        var result = await controller.NumberOfGummyBearsForUser("123");

        // Assert
        Assert.Equal(100, result);
    }

错误看起来像这样

enter image description here

我认为我需要通过更多的操作来创建该usermanager对象,但是我不确定我找到的所有教程都使用ApplicationUser而不是IdentityUser,所以我对如何模拟该对象感到困惑。

2 个答案:

答案 0 :(得分:6)

您只需

// Arrange
var mockUser = new Mock<UserManager<IdentityUser>>();

var controller = new SweetController(mockUser.Object);

您不需要

var userManager = new UserManager(mockRepo.Object);  <-- error here see image below
完全

mockUser已经是模拟的UserManager<T>,您可以通过mock.Object放置模拟的实例。

当模拟对象时,您不必使用其所有依赖关系实例化该对象(这将是集成测试),这就是模拟的重点(连同使方法返回所需的值并进行行为测试以确保您测试的代码调用了带有模拟对象特定参数的特定方法。

当然,上面的代码本身是行不通的,因为您没有为FindByIdAsyncIsInRoleAsync设置任何测试条件/返回值。您必须使用

进行设置
mockUser.Setup( userManager => userManager.FindByIdAsync(It.IsAny<string>()))
    .ReturnsAsync(new IdentityUser { ... });
mockUser.Setup( userManager => userManager.IsInRoleAsync(It.IsAny<IdentityUser>(), "SweetTooth"))
    .ReturnsAsync(true);

然后,无论何时调用该模拟,它都会返回您的预定义用户和预定义结果。

答案 1 :(得分:0)

在曾(Tseng)的帮助下,我成功了。完整的版本是

控制器

   private readonly UserManager<IdentityUser> _userManager;

    public SweetController(UserManager<IdentityUser> userManager)
    {
        _userManager = userManager;
    }

    public async Task<IdentityUser> GetUser(string userId)
    {
        var user = await _userManager.FindByIdAsync(userId);
        return user;
    }

测试

[Fact]
    public async Task Test1()
    {
        // Arrange
        var store = new Mock<IUserStore<IdentityUser>>();
        store.Setup(x => x.FindByIdAsync("123", CancellationToken.None))
            .ReturnsAsync(new IdentityUser()
            {
                UserName = "test@email.com",
                Id = "123"
            });

        var mgr = new UserManager<IdentityUser>(store.Object, null, null, null, null, null, null, null, null);

        var controller = new SweetController(mgr);

        // Act
        var result = await controller.GetUser("123");

        // Assert
        Assert.NotNull(result);
        Assert.Equal("123", result.Id);
    }

我删除了角色检查,只是为了使其尽可能基本地工作。