Reputation: 980
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
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