簡體   English   中英

帶有UserManager的ASP.NET 5單元測試控制器

[英]ASP.NET 5 Unit Test controller with UserManager

我開始使用ASP.NET 5(vNext),現在嘗試對使用UserManager注冊和登錄用戶的控制器進行單元測試。

我正在使用xUnitmoq.netcore

在我的UnitTest中,我有:

var mockStore = new Mock<IUserStore<ApplicationUser>>(MockBehavior.Strict).As<IUserPasswordStore<ApplicationUser>>();

mockStore.Setup(x => x.CreateAsync(It.IsAny<ApplicationUser>(), CancellationToken.None)).Returns(Task.FromResult(new IdentityResult()));

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

以及控制器中的代碼:

var result = await _securityManager.CreateAsync(user, model.Password);

但是,當我運行單元測試時,調用CreateAsync時會得到一個空異常。

我不明白為什么我不能使用ApplicationUser和字符串參數來模擬CreateAsync方法,而我必須使用CancellationToken來模擬它。

這是我的第一個使用ASP.NET 5的項目,之前我使用過ASP.NET 4.6,所以現在很多事情有所不同。

而且,您是否認為我應該已經在ASP.NET 5中開發了一個重要項目,還是應該等待並為ASP.NET 4.6開發它?

在嘗試了很多事情之后,我想出了一個可行的解決方案。

用戶管理器

我創建了一個FakeUserManager類,該類繼承了UserManager並覆蓋了CreateAsync方法。

public class FakeUserManager : UserManager<ApplicationUser>
{
    public FakeUserManager()
        : base(new Mock<IUserStore<ApplicationUser>>().Object,
              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,
              new Mock<IHttpContextAccessor>().Object)
    { }

    public override Task<IdentityResult> CreateAsync(ApplicationUser user, string password)
    {
        return Task.FromResult(IdentityResult.Success);
    }
}

然后,我將新的FakeUserManager實例傳遞給AccountController構造函數,並且工作正常。


登錄管理器

對於那些可能需要模擬SignInManager的用戶,我可以通過以下方式進行操作:

我創建了一個FakeSignInManager類,該類繼承了SignInManager並覆蓋了我需要的方法。

public class FakeSignInManager : SignInManager<ApplicationUser>
{
    public FakeSignInManager(IHttpContextAccessor contextAccessor)
        : base(new FakeUserManager(),
              contextAccessor,
              new Mock<IUserClaimsPrincipalFactory<ApplicationUser>>().Object,
              new Mock<IOptions<IdentityOptions>>().Object,
              new Mock<ILogger<SignInManager<ApplicationUser>>>().Object)
    {
    }

    public override Task SignInAsync(ApplicationUser user, bool isPersistent, string authenticationMethod = null)
    {
        return Task.FromResult(0);
    }

    public override Task<SignInResult> PasswordSignInAsync(string userName, string password, bool isPersistent, bool lockoutOnFailure)
    {
        return Task.FromResult(SignInResult.Success);
    }

    public override Task SignOutAsync()
    {
        return Task.FromResult(0);
    }
}

由於SignInManager需要上下文訪問器才能工作,因此我使FakeSignInManager在構造函數中接收它。

然后,在創建SignInManager的新實例之前,請按以下方式准備新的HttpContextAccessor:

var context = new Mock<HttpContext>();
var contextAccessor = new Mock<IHttpContextAccessor>();
contextAccessor.Setup(x => x.HttpContext).Returns(context.Object);

然后創建新的FakeSignInManager實例:

new FakeSignInManager(contextAccessor.Object);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM