Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add claims in a mock ClaimsPrincipal

I am trying to unit test my controller code which gets the information from the ClaimsPrincipal.Current. In the controller code I

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

And I am trying to mock my ClaimsPrincipal with claims but I still don't have any mock value from the claim.

// 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")); 

The viewresult.Content is empty as I run the unit test. Any help if I can add the mock claim. Thanks.

like image 523
Henry Avatar asked Jul 12 '16 08:07

Henry


People also ask

What are principal claims?

Principal Claims means the claims for the repayment of principal under a Loan Agreement.

What is ClaimsPrincipal in. net Core?

ClaimsPrincipal exposes a collection of identities, each of which is a ClaimsIdentity. In the common case, this collection, which is accessed through the Identities property, will only have a single element.


2 Answers

You don't need to mock ClaimsPrincipal it has no outside dependencies and you can created it un-mocked:

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

And I'm not sure what you are testing here. Certainly "John Doe" will not be part of viewResult.Content because it is never been set to this.

like image 112
trailmax Avatar answered Sep 19 '22 12:09

trailmax


First, you are missing this line in your test:

Thread.CurrentPrincipal = cp.Object;   

(and then cleaning it up in TearDown).

Second, as @trailmax mentioned, mocking principal objects is impractical. In your case, ClaimsPrincipal.FindFirst (according to decompiled source) looks into private fields of its instance, that's the reason mocking didn't help.

I prefer using two simple classes that allow me to unit test claims-based functionality:

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

then your test shrinks down to:

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

and it now passes, I've just verified.

like image 32
felix-b Avatar answered Sep 21 '22 12:09

felix-b