【问题标题】:mock GetClaimsPrincipal().Identity模拟 GetClaimsPrincipal().Identity
【发布时间】:2016-04-20 06:19:00
【问题描述】:

我无法在下面的代码行中找到模拟。

ClaimsPrincipalFactory userClaimsPrincipal = new UserClaimsPrincipalFactory();
System.Security.Claims.ClaimsIdentity claimIdentity = userClaimsPrincipal.GetClaimsPrincipal().Identity as System.Security.Claims.ClaimsIdentity;

当我尝试模拟时,我得到了错误

Microsoft.Owin.Host.SystemWeb.dll 中出现“System.NullReferenceException”类型的异常,但未在用户代码中处理

在下面的代码中。

public class UserClaimsPrincipalFactory : ClaimsPrincipalFactory
{
    protected override ClaimsPrincipal OnGetClaimsPrincipal()
    {
        return HttpContext.Current.GetOwinContext().Authentication.User;
    }
}

我试过的模拟

Mock<UserClaimsPrincipalFactory> mockUserClaimsPrincipal = new Mock<UserClaimsPrincipalFactory>();
mockUserClaimsPrincipal
    .Setup(ucp => ucp.GetClaimsPrincipal().Identity).Returns("Need to set");

任何人都可以帮助我。提前致谢。

【问题讨论】:

  • ClaimsPrincipalFactory 是自定义类吗?如果可以,您可以包含该类的定义。
  • 你真正想测试什么? claimIdentity 是否正在生成以成为更大测试的一部分?
  • 该异常与HttpContext的紧密耦合有关

标签: c# unit-testing mocking moq claims-based-identity


【解决方案1】:

如果下面的代码...

ClaimsPrincipalFactory userClaimsPrincipal = new UserClaimsPrincipalFactory();
ClaimsIdentity claimIdentity = userClaimsPrincipal.GetClaimsPrincipal().Identity as ClaimsIdentity;

被用作更大测试的一部分,您需要claimIdentity 变量,然后您需要抽象UserClaimsPrincipalFactory,因为此类的具体实现与HttpContext 紧密耦合,在此期间将为空你的测试,除非你也嘲笑HttpContext(你不应该这样做:Don't mock HttpContext: He doesn't like to be mocked!

如果最终目标是获得ClaimsPrincipal/ClaimsIdentity,那么您可以将该要求抽象为服务。

public interface IClaimsPrincipalFactory {
    ClaimsPrincipal GetClaimsPrincipal();
}

这样您就可以在不直接依赖HttpContext 的情况下进行测试。

这里的假设是您可以直接控制ClaimsPrincipalFactory 类并且可以重构它......

public abstract class ClaimsPrincipalFactory : IClaimsPrincipalFactory {
    public ClaimsPrincipal GetClaimsPrincipal() {
        ClaimsPrincipal result = OnGetClaimsPrincipal();
        //...other code
        return result;
    }
    protected abstract ClaimsPrincipal OnGetClaimsPrincipal();
}

完成后,单元测试看起来像......

[TestMethod]
public void Factory_Should_Get_Claims_Principal() {
    //Arrange
    var fakeIdentity = new ClaimsIdentity();
    var mockUserClaimsPrincipal = new Mock<IClaimsPrincipalFactory>();
    mockUserClaimsPrincipal.Setup(ucp => ucp.GetClaimsPrincipal().Identity).Returns(fakeIdentity);

    IClaimsPrincipalFactory userClaimsPrincipal = mockUserClaimsPrincipal.Object;
    System.Security.Claims.ClaimsIdentity claimIdentity = userClaimsPrincipal.GetClaimsPrincipal().Identity as System.Security.Claims.ClaimsIdentity;

    //Act
    //...other code that uses the claimIdentity


    //Assert
    //...other assertions
}

【讨论】:

    【解决方案2】:

    您可以使用Typemock Isolator 完成此操作。 Isolate.WhenCalled() 模拟 OnGetClaimsPrincipal(),所以它根本不接触 HttpContext,并返回所需的 ClaimsPrincipal。看例子:

    public void TestGetClaimsPrincipal()
    {
        //Arrange 
        var claims = new List<Claim>();
        claims.Add(new Claim(ClaimTypes.Name, "Name"));
        claims.Add(new Claim(ClaimTypes.Email, "name@gmail.com"));
        var myIdentity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
        var myPrincipal = new ClaimsPrincipal(myIdentity);
        var target = new UserClaimsPrincipalFactory();
        Isolate.NonPublic.WhenCalled(target, "GetClaimsPrincipal").WillReturn(myPrincipal);
    
        //Act
        var result = Isolate.Invoke.Method(target, "GetClaimsPrincipal") as ClaimsPrincipal;
    
        //Assert
        Assert.AreEqual("Name", result.Identity.Name);
    }
    

    希望对你有帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-01
      • 2021-12-02
      • 2014-06-22
      • 1970-01-01
      • 2019-11-19
      • 2015-07-16
      • 2010-12-23
      • 2021-04-01
      相关资源
      最近更新 更多