Abhilash Gopalakrishna
Abhilash Gopalakrishna

Reputation: 980

NUnit Test UserManager, roleManager in ASP.NET Core

I am trying to write unit tests for my controller which uses the User Manager and Role Manager.

I have operations, which are involved in creating users, creating roles, and adding and removing users to and from roles.

I am passing the usermanager, signInManager as dependencies through the controller constructor.

private readonly IHostingEnvironment hostingEnvironment;

public IHostingEnvironment HostingEnvironment => hostingEnvironment;

public AdminController(IHostingEnvironment environment, SignInManager<IdentityUser> signInManager, ILogger<LoginModel> logger, RoleManager<IdentityRole> roleManager, UserManager<IdentityUser> userManager)
{
    _signInManager = signInManager;
    _logger = logger;
    _roleManager = roleManager;
    _userManager = userManager;
    hostingEnvironment = environment;
}

I need to test whether the users are being successfully added to the roles, removed from the roles, etc.

I don't want to test the services themselves, but operations only.

I have decoupled the operations as follows to capture any exceptions.

public async Task<bool> AddUserToRole(IdentityUser user, string role)
{
    try
    {
        var addUserToRole = await _userManager.AddToRoleAsync(user, role);
        if (addUserToRole.Succeeded)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    catch(Exception e)
    {
        throw new Exception("OperationFailed");
    }

    return false;

}

Similarly I have decoupled all operations involving the userManager and called the above functions in the controller action.

For testing I have done the following:

    [TestFixture]
    public class AdminControllerTest
    {
        protected TestContext db;
        protected Context _db;
        protected SignInManager<IdentityUser> signInManager;
        protected ILogger<LoginModel> logger;
        protected RoleManager<IdentityRole> roleManager;
        protected UserManager<IdentityUser> userManager;
        protected IHostingEnvironment hostingEnvironment;

        [TestCase]
        public void Verify_AdminController_Is_Decorated_With_Authorize_Attribute()
        {
            var userEmail = _db.AspNetUsers.Select(x => x.Email).FirstOrDefault();
            var user =await userManager.FindByEmailAsync(userEmail);

            var userRole = "Supervisor";
            AdminController adminController = new AdminController(hostingEnvironment, signInManager, logger, roleManager, userManager);
            var actionResult = adminController.AddUserToRole(user, userRole).Result;
            Assert.IsTrue(actionResult);
        }

The above doesn't work.

I tried mocking the services by using Moq. But if I mock the services I cannot pass them to the controller instance.

If I mock the controller itself, I am not able to use its actions; it returns Null;

I don't completely understand the concept of mocking.

What is the best way to go about solving the above problem?

I am using ASP.NET Core 2.1 and NUnit 3.0.

Upvotes: 1

Views: 1326

Answers (1)

Shahar Shokrani
Shahar Shokrani

Reputation: 8762

It looks like you have not yet decoupled the dependencies out from the AdminController constructor.

Instead of passing the implementation, you will need to pass the abstraction/interfaces:

public AdminController(IHostingEnvironment environment,
                       ISignInManager<IdentityUser> signInManager,
                       ILogger<LoginModel> logger,
                       IRoleManager<IdentityRole> roleManager,
                       IUserManager<IdentityUser> userManager)

Note that I've only added the I prefix, but it mean will need to refactor your code to pass an interfaces as I mentioned.

Now, we can mock the AdminController easily with:

[TestFixure]
public class AdminControllerTests
{
    private AdminController _adminController;
    private IHostingEnvironment _hostingEnvironment = new Mock<IHostingEnvironment>();
    private ISignInManager<IdentityUser> _signInManager = new Mock<ISignInManager<IdentityUser>>();

The _signInManager will need a setup that uses the method that returns ISignInManager within your ISignInManager, lets assume its name its Builder().

Note: There are other ways of mocking. Here are two ways, or consider using autofac.

    [SetUp]
    public void SetUp()
    {
        _signInManager.Setup(a => a.Builder()).Returns(new[] { new IdentityUser() });
        // Do the same for the rest of the dependencies.
        //...
        _adminController = new AdminController(_hostingEnvironment, _signInManager.Object, ...);
    }

Now you can make use of the _adminController instance (see the proper naming convention for test methods):

    [Test]
    public void Verify_AdminController_Is_Decorated_With_Authorize_Attribute()
    {
        //...
        var actionResult = _adminController.AddUserToRole(user, userRole).Result;
        // ...
    }
}

Upvotes: 2

Related Questions