2016-07-12 1 views
10

ClaimsPrincipal.Current에서 정보를 가져 오는 컨트롤러 코드를 단위 테스트하려고합니다. 컨트롤러 코드에서 내가mock에 클레임을 추가하는 방법 ClaimsPrincipal

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

단위 테스트를 실행하면 viewresult.Content가 비어 있습니다. 모의 주장을 추가 할 수 있다면 도움이됩니다. 감사.

답변

15

첫째, 당신은 테스트에서이 줄을 누락되었습니다.

둘째로, @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) 
     { 
     } 
    } 

다음 테스트가 아래로 축소 : 그것은 지금

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

와 내가했습니다, 통과 방금 확인했습니다.

+0

고마워요! 나는 그것을 복잡하게 만들고 있다고 생각한다. 언제 우리는 실제로'ClaimsPrincipal'을 조롱해야합니까? Google에서 확인한 이후 많은 사람들이'ClaimsPrincipal'을 조롱하고 있습니다. 이런, http://stackoverflow.com/questions/14190066/is-there-any-way-i-can-mock-a-claims-principal-in-my-asp-net-mvc-web-application. – Henry

+0

당신은 환영합니다 :) 그 대답은 SUT가 HasClaim 메소드만을 호출 할 것이라는 가정은 너무 연약합니다. SUT (아마도 제 3 자 코드)가 교장의 추가 구성원을 액세스해야하는 경우 테스트가 중단됩니다. 필자는 종종 의존성을 수동으로 서브 클래 싱하여 "테스트 방법"으로 구현하는 것을 선호하지만 여전히 일관성있게 작동하는지 확인합니다. –

+0

Brilliant! 나를 위해 완벽하게 일했습니다. 고맙습니다! –

13

당신은하지 외부 종속성이 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의 일부가 아닙니다. (분해에 청소 후와)

Thread.CurrentPrincipal = cp.Object; 

을 :

관련 문제