Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET 5 Unit Test controller with UserManager

I started to use ASP.NET 5 (vNext) and now I'm trying to unit test a controller that uses UserManager to register and login users.

I'm using xUnit and moq.netcore.

In my UnitTest I have:

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

And the code in the controller:

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

But, when I run the unit test I get a null exception, when calling CreateAsync.

I don't understand why I can't Mock the CreateAsync method with ApplicationUser and string parameters, and I have to mock it with the CancellationToken.

It's my first project using ASP.NET 5, I was using ASP.NET 4.6 before, so a lot of things are different now.

And, do you think I should already develop an important project in ASP.NET 5 or should I wait and develop it for ASP.NET 4.6?

like image 629
Kevin Amorim Avatar asked Feb 25 '16 12:02

Kevin Amorim


1 Answers

After trying a lot of things I came up with a working solution.

UserManager

I created a FakeUserManager class that inherits UserManager and overrides CreateAsync method.

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

Then I passed a new instance of FakeUserManager to AccountController constructor and it works fine.


SignInManager

And for those that may need to mock SignInManager I did it the following way:

I created a FakeSignInManager class that inherits SignInManager and overrides the methods I need.

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

And since SignInManager need a context accessor to work I made FakeSignInManager receive it in the constructor.

Then, before creating a new instance of SignInManager I prepare a new HttpContextAccessor the following way:

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

And then create the new FakeSignInManager instance:

new FakeSignInManager(contextAccessor.Object);
like image 114
Kevin Amorim Avatar answered Nov 06 '22 18:11

Kevin Amorim