如何在模拟的ClaimsPrincipal中添加声明

Hen*_*nry 26 .net c# unit-testing moq asp.net-mvc-5

我正在尝试对我的控制器代码进行单元测试,该代码从ClaimsPrincipal.Current获取信息.在控制器代码中

public class HomeController {
    public ActionResult GetName() {
        return Content(ClaimsPrincipal.Current.FindFirst("name").Value);
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图用索赔来嘲笑我的ClaimsPrincipal,但我仍然没有任何模拟价值.

// Arrange
IList<Claim> claimCollection = new List<Claim>
{
    new Claim("name", "John Doe")
};

var identityMock = new Mock<ClaimsIdentity>();
identityMock.Setup(x => x.Claims).Returns(claimCollection);

var cp = new Mock<ClaimsPrincipal>();
cp.Setup(m => m.HasClaim(It.IsAny<string>(), It.IsAny<string>())).Returns(true);
cp.Setup(m => m.Identity).Returns(identityMock.Object);

var sut = new HomeController();

var contextMock = new Mock<HttpContextBase>();
contextMock.Setup(ctx => ctx.User).Returns(cp.Object);

var controllerContextMock = new Mock<ControllerContext>();
controllerContextMock.Setup(con => con.HttpContext).Returns(contextMock.Object);
controllerContextMock.Setup(con => con.HttpContext.User).Returns(cp.Object);

sut.ControllerContext = controllerContextMock.Object;

// Act
var viewresult = sut.GetName() as ContentResult;

// Assert
Assert.That(viewresult.Content, Is.EqualTo("John Doe"));
Run Code Online (Sandbox Code Playgroud)

viewresult.Content是空的,因为我运行单元测试.如果我可以添加模拟声明,任何帮助.谢谢.

tra*_*max 60

你不需要模拟ClaimsPrincipal它没有外部依赖关系,你可以创建它没有模拟:

var claims = new List<Claim>() 
{ 
    new Claim(ClaimTypes.Name, "username"),
    new Claim(ClaimTypes.NameIdentifier, "userId"),
    new Claim("name", "John Doe"),
};
var identity = new ClaimsIdentity(claims, "TestAuthType");
var claimsPrincipal = new ClaimsPrincipal(identity);
Run Code Online (Sandbox Code Playgroud)

而且我不确定你在这里测试什么.当然,"John Doe"不会成为其中的一部分,viewResult.Content因为它从未被置于此之中.

  • 无法对此进行足够的投票,应该是公认的答案! (5认同)
  • 你是英雄。 (2认同)

fel*_*x-b 31

首先,您在测试中缺少此行:

Thread.CurrentPrincipal = cp.Object;  
Run Code Online (Sandbox Code Playgroud)

(然后在TearDown中清理它).

其次,正如@trailmax所提到的,模拟主要对象是不切实际的.在你的情况下,ClaimsPrincipal.FindFirst(根据反编译的源代码)查看其实例的私有字段,这就是模拟没有帮助的原因.

我更喜欢使用两个简单的类来允许我对基于声明的功能进行单元测试:

    public class TestPrincipal : ClaimsPrincipal
    {
        public TestPrincipal(params Claim[] claims) : base(new TestIdentity(claims))
        {
        }
    }

    public class TestIdentity : ClaimsIdentity
    {
        public TestIdentity(params Claim[] claims) : base(claims)
        {
        }
    }
Run Code Online (Sandbox Code Playgroud)

然后你的测试缩小到:

    [Test]
    public void TestGetName()
    {
        // Arrange
        var sut = new HomeController();
        Thread.CurrentPrincipal = new TestPrincipal(new Claim("name", "John Doe"));

        // Act
        var viewresult = sut.GetName() as ContentResult;

        // Assert
        Assert.That(viewresult.Content, Is.EqualTo("John Doe"));
    }
Run Code Online (Sandbox Code Playgroud)

它现在通过了,我刚刚验证过.