Moq不会调用IAuthenticationManager SignIn方法

时间:2018-03-19 09:16:34

标签: c# asp.net-mvc unit-testing asp.net-identity moq

我试图通过验证一次调用AuthenticationManager SignIn方法来运行成功登录的单元测试这是我得到的错误:

  

消息:测试方法Portfolio.UnitTest.WebUI.Controllers.LoginControllerTests.Login_Verified_Authenticates_System_User引发异常:   Moq.MockException:   在模拟上预期调用一次,但是是0次:m => m.SignIn(AuthenticationProperties,[ClaimsIdentity])

     

已配置的设置:   m => m.SignIn(AuthenticationProperties,[ClaimsIdentity])

     

执行调用:   IAuthenticationManager.SignIn(AuthenticationProperties,[ClaimsIdentity])

即使错误信息似乎也是自相矛盾的。

我的控制器类/方法:

public class LoginController : ProjectBaseController
{
private IAuthenticationManager _authenticationManager;
    public IAuthenticationManager AuthenticationManager
    {
        get
        {
            return _authenticationManager ?? HttpContext.GetOwinContext().Authentication;
        }
        set
        {
            _authenticationManager = value;
        }
    }
[HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public ActionResult Index(LoginViewModel accountUser)
    {
        if (!ModelState.IsValid)
            return View(accountUser);

        var systemUser = _authenticationService.Verify(accountUser.Email, accountUser.Password);
        if (systemUser == null)
        {
            ModelState.AddModelError("", "Invalid email address or password");
            return View(accountUser);
        }

        var identity = new ClaimsIdentity
        (
            new[] 
            {
                new Claim(ClaimTypes.Name, systemUser.FullName),
                new Claim(ClaimTypes.Email, systemUser.Email)
            },
            DefaultAuthenticationTypes.ApplicationCookie,
            ClaimTypes.Name, 
            ClaimTypes.Role
        );

        // Set roles for authorization attributes used throughout dashboard
        foreach(var role in systemUser.Roles)
        {
            identity.AddClaim(new Claim(ClaimTypes.Role, role.Name));
        }

        AuthenticationManager.SignIn
        (
            new AuthenticationProperties
            {
                IsPersistent = true
            }, 
            identity
        );

        return Redirect(accountUser.ReturnUrl);   
    }

LoginControllerTests:

[TestClass]
public class LoginControllerTests
{
    private readonly Mock<IAuthenticationManager> _mockAuthenticationManager;
    private readonly Mock<IAuthenticationService> _mockAuthenticationService;

    public LoginControllerTests()
    {
        _mockAuthenticationManager = new Mock<IAuthenticationManager>();
        _mockAuthenticationService = new Mock<IAuthenticationService>();
    }

    private LoginController GetLoginControllerInstance()
    {
        var controller = new LoginController(_mockAuthenticationService.Object);
        controller.AuthenticationManager = _mockAuthenticationManager.Object;

        return controller;
    }

    [TestMethod]
    public void Login_Verified_Authenticates_System_User()
    {
        // Arrange
        var viewModel = new LoginViewModel("/")
        {
            Email = "email@test.co.uk",
            Password = "password-test"
        };
        var systemUser = new SystemUser()
        {
            Id = new Random().Next(),
            FirstName = "Joe",
            LastName = "Bloggs",
            Email = viewModel.Email,
            Password = viewModel.Password,
            Roles = new List<Role>()
        };
        var identity = new ClaimsIdentity
        (
            new[]
            {
                new Claim(ClaimTypes.Name, systemUser.FullName),
                new Claim(ClaimTypes.Email, systemUser.Email)
            },
            DefaultAuthenticationTypes.ApplicationCookie,
            ClaimTypes.Name,
            ClaimTypes.Role
        );
        var authenticationProperty = new AuthenticationProperties
        {
            IsPersistent = true
        };

        var controller = this.GetLoginControllerInstance();
        _mockAuthenticationService.Setup(m => m.Verify(viewModel.Email, viewModel.Password))
            .Returns(systemUser);
        _mockAuthenticationManager.Setup(m => m.SignIn(authenticationProperty, identity));

        // Act
        var result = controller.Index(viewModel);

        // Assert
        Assert.IsNotNull(result);
        Assert.IsTrue(controller.ModelState.IsValid);
        _mockAuthenticationService.Verify(m => m.Verify(viewModel.Email, viewModel.Password), Times.Once);
        _mockAuthenticationManager.Verify(m => m.SignIn(authenticationProperty, identity), Times.Once);
    }
}
}

在deubg中运行该方法在控制器内调用就好了但是Moq似乎忽略了它。

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

Nkosi在评论你的问题时说:

在表达式

m => m.SignIn(authenticationProperty, identity)

两个参数authenticationPropertyidentity必须是&#34;相等&#34;实际传入的两个参数(通过System-Under-Test)。那么Equals在比较时会返回true吗?

如果需要,您可以使用It.IsAny<AuthenticationProperties>()It.Is((AuthenticationProperties x) => x.IsPersistent)或类似内容。与ClaimsIdentity类似。然后Moq将不再需要Equals平等。