ASP.NET Core 中的 NUnit 测试 UserManager、roleManager

NUnit Test UserManager, roleManager in ASP.NET Core

我正在尝试为使用 User ManagerRole Manager.

的控制器编写单元测试

我有操作,涉及到创建用户、创建角色,以及在角色中添加和删除用户。

我正在通过控制器构造函数将 usermanager、signInManager 作为依赖项传递。

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

我需要测试用户是否成功添加到角色、从角色中删除等

我不想测试服务本身,只想测试操作。

我已将操作解耦如下以捕获任何异常。

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;

}

同样,我解耦了所有涉及 userManager 的操作,并在控制器操作中调用了上述函数。

为了测试,我做了以下工作:

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

上面的方法不行。

我尝试使用 Moq 模拟服务。但是如果我模拟服务,我不能将它们传递给控制器​​实例。

如果我模拟控制器本身,我将无法使用它的动作;它 returns 空;

我不完全理解模拟的概念。

解决上述问题的最佳方法是什么?

我正在使用 ASP.NET Core 2.1 和 NUnit 3.0。

看起来您还没有将依赖项与 AdminController 构造函数分离。

您需要传递 abstraction/interfaces:

而不是传递实现
public AdminController(IHostingEnvironment environment,
                       ISignInManager<IdentityUser> signInManager,
                       ILogger<LoginModel> logger,
                       IRoleManager<IdentityRole> roleManager,
                       IUserManager<IdentityUser> userManager)

请注意,我只添加了 I 前缀,但这意味着需要重构您的代码以传递我提到的接口。

现在,我们可以通过以下方式轻松模拟 AdminController

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

_signInManager 需要一个使用 ISignInManager 中的 returns ISignInManager 方法的设置,假设它的名字是 Builder().

注意:还有其他的模拟方式。这里是 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, ...);
    }

现在您可以使用 _adminController 实例(测试方法见 proper naming convention):

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