Как добавить претензии в mock ClaimsPrincipal

Я пытаюсь unit test мой код контроллера, который получает информацию из ClaimsPrincipal.Current. В коде контроллера I

public class HomeController {
    public ActionResult GetName() {
        return Content(ClaimsPrincipal.Current.FindFirst("name").Value);
    }
}

И я пытаюсь издеваться над претензиями 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"));

. view view.Content пуст, поскольку я запускаю unit test. Любая помощь, если я могу добавить иск. Спасибо.

Ответ 1

Во-первых, вам не хватает этой строки в вашем тесте:

Thread.CurrentPrincipal = cp.Object;  

(а затем очистите его в TearDown).

Во-вторых, как упоминал @trailmax, издевательские главные объекты непрактичны. В вашем случае ClaimsPrincipal.FindFirst (в соответствии с декомпилированным исходным кодом) просматривает частные поля своего экземпляра, что причина, по которой насмехается, не помогла.

Я предпочитаю использовать два простых класса, которые позволяют мне использовать unit test на основе утверждений:

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

    public class TestIdentity : ClaimsIdentity
    {
        public TestIdentity(params Claim[] claims) : base(claims)
        {
        }
    }

тогда ваш тест сжимается до:

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

и теперь он проходит, я только что подтвердил.

Ответ 2

Вам не нужно издеваться над 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);

И я не уверен, что вы здесь тестируете. Конечно, "John Doe" не будет частью viewResult.Content, потому что он никогда не был установлен на этом.