如何在ASP MVC 5(Microsoft.AspNet.Identity)中存根User.Identity.GetUserId()

时间:2013-12-09 15:11:57

标签: unit-testing asp.net-mvc-5 asp.net-identity

如何在ASP MVC 5(Microsoft.AspNet.Identity)中存储User.Identity.GetUserId()以进行MVC5控制器的单元测试? GetUserId()是一个扩展,所以我不能直接模拟它。我需要在测试前分配Id。 您似乎必须创建一个Claim并将其分配给GenericIdentity。但是单元测试似乎要做很多事情。你知道其他选择吗?

3 个答案:

答案 0 :(得分:12)

非常感谢你的想法。我正在使用NSubstitute。我没有Microsoft Fakes和JustMock。所以我直接将声明填充到GenericIdentity,因此我可以控制UserId的值:

string username = "username";
string userid = Guid.NewGuid().ToString("N"); //could be a constant

List<Claim> claims = new List<Claim>{
    new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", username), 
    new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", userid)
};
var genericIdentity = new GenericIdentity("");
genericIdentity.AddClaims(claims);
var genericPrincipal = new GenericPrincipal(genericIdentity, new string[] { "Asegurado" });
controllerContext.HttpContext.User = genericPrincipal;

答案 1 :(得分:4)

准备好一些痛苦?

它将在很大程度上取决于您使用的模拟框架。根据我的假设你使用Moq然后你有点不幸,因为Moq没有做得很好。原因是Moq不能模拟扩展方法(实际上它can但你不应该/不应该这样做:-))

如果你正在使用像JustMock这样的另一个模拟框架,那么你的里程可能会有所不同。根据{{​​3}},这比看到的要容易得多。

我找到的最简单的方法(这仍然远非易事)是使用this

大多数新标识内容都是使用扩展接口编写的。我不能为我的生活弄清楚为什么他们认为这是一个好主意,但你有。

这是你需要做的。

首先为Microsoft.AspNet.Identity创建假装配。您可以通过右键单击程序集并选择“添加假装配”来执行此操作。这实际上是遍历程序集并为它在那里找到的所有内容创建了填充程序和存根。你想要做的是将呼叫调整到GetUserId,...实际上这并不太难。

然后你必须通过它非常熟悉的声音来定期模仿ControllerContext

我认为以下代码可以满足您的需求 -

        using (var context = ShimsContext.Create())
        {
            Microsoft.AspNet.Identity.Fakes
                .ShimIdentityExtensions.GetUserIdIIdentity =
            (i) => "Mr. T";

            var fakeHttpContext = new Mock<HttpContextBase>();
            var fakeIdentity = new GenericIdentity("User");
            var principal = new GenericPrincipal(fakeIdentity, null);

            fakeHttpContext.Setup(t => t.User).Returns(principal);

            var controllerContext = new Mock<ControllerContext>();
            controllerContext.Setup(t => t.HttpContext)
                .Returns(fakeHttpContext.Object);

            var sut = new HomeController();
            sut.ControllerContext = controllerContext.Object;

            var result = sut.YourTestAction();
            Assert.True(result.WhatYouCareAbout);
        }

当然,它不一定是T先生。

HTH

答案 2 :(得分:0)

您可以创建从MvcContrib.TestHelper.Fakes中的对象继承的伪主体和/或标识

然后你可以这样做:

        using (var userManager = _userManagerFactory.CreateUserManager())
        {
            var userId = Guid.NewGuid().ToString();
            var result = userManager.CreateAsync(new IdentityUser() { Id = userId, UserName = "userName" }, "password").Result;

            Assert.IsTrue(result.Succeeded, "failed to create user through usermanager");

            var fakePrincipal = new FakePrincipal(new FakeClaimIdentity(userId, "userName"), new[] { "SomeRole" });

            Assert.IsTrue(fakePrincipal.Identity.IsAuthenticated, "fake user did not come back authenticated");

        }

我以前用来制作虚假声明身份的课程是这样的:

using System.Collections.Generic;
using System.Security.Claims;
using MvcContrib.TestHelper.Fakes;

namespace Tests.Unit.Fakes
{
    public class FakeClaimIdentity : ClaimsIdentity
    {

        private readonly FakeIdentity _fakeIdentity;


        public FakeClaimIdentity(string id, string userName) : base(userName)
        {
            _fakeIdentity = new FakeIdentity(userName);
            base.AddClaims(new List<Claim>
            {
                new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", userName),
                new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", id)
            });
        }

        public override bool IsAuthenticated
        {
            get { return _fakeIdentity.IsAuthenticated; }
        }

        public override string Name
        {
            get { return _fakeIdentity.Name; }
        }

        public override string AuthenticationType
        {
            get
            {
                return _fakeIdentity.AuthenticationType;
            }
        }
    }
}

这样也可以测试IsAuthenticated部分(如果你关心身份的有效性)。