简体   繁体   中英

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 believe this is because; the userManager in the DevProject and the Test Project are different instances.

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.

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;
        // ...
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM