gpt4 book ai didi

c# - 我如何模拟 User.Identity.GetUserId()?

转载 作者:IT王子 更新时间:2023-10-29 04:10:44 26 4
gpt4 key购买 nike

我正在尝试对包含以下行的代码进行单元测试:

UserLoginInfo userIdentity = UserManager.GetLogins(User.Identity.GetUserId()).FirstOrDefault();

我只是停留在一点上,因为我无法得到:

User.Identity.GetUserId()

返回一个值。我一直在尝试以下设置我的 Controller :

var mock = new Mock<ControllerContext>();
mock.Setup(p => p.HttpContext.User.Identity.GetUserId()).Returns("string");

但它给出了“NotSupportedException 未被用户代码处理”的错误。我还尝试了以下方法:

ControllerContext controllerContext = new ControllerContext();

string username = "username";
string userid = Guid.NewGuid().ToString("N"); //could be a constant

List<Claim> claims = new List<Claim>{
new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", username),
new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", userid)
};
var genericIdentity = new GenericIdentity("Andrew");
genericIdentity.AddClaims(claims);
var genericPrincipal = new GenericPrincipal(genericIdentity, new string[] { });
controllerContext.HttpContext.User = genericPrincipal;

基于我在 stackoverflow 上找到的一些代码,但这会返回相同的错误“NotSupportedException 未被用户代码处理”。

任何关于我如何进行的帮助都将不胜感激。谢谢。

最佳答案

您不能直接模拟扩展方法,因此最好的办法是向下钻取,直到找到可模拟的扩展方法所依赖的属性和方法。

在这种情况下,IIdentity.GetuUserId() 是一个扩展方法。我会发布它,但该库目前不是开源的,因此您必须自己查看 GetUserId() 是否依赖于 ClaimsIdentity.FindFirstValue()。事实证明,这也是一种扩展方法,但它依赖于标记为 virtualClaimsIdentity.FindFirst()。现在我们有了接缝,所以我们可以执行以下操作:

var claim = new Claim("test", "IdOfYourChoosing");
var mockIdentity =
Mock.Of<ClaimsIdentity>(ci => ci.FindFirst(It.IsAny<string>()) == claim);
var controller = new MyController()
{
User = Mock.Of<IPrincipal>(ip => ip.Identity == mockIdentity)
};

controller.User.Identity.GetUserId(); //returns "IdOfYourChoosing"

更新:我刚刚意识到我上面发布的解决方案仅适用于派生的 ApiControllers(如 Web API)。 MVC Controller 类没有可设置的 User 属性。幸运的是,很容易通过 ControllerControllerContext 来达到预期的效果:

var claim = new Claim("test", "IdOfYourChoosing");
var mockIdentity =
Mock.Of<ClaimsIdentity>(ci => ci.FindFirst(It.IsAny<string>()) == claim);
var mockContext = Mock.Of<ControllerContext>(cc => cc.HttpContext.User == mockIdentity);
var controller = new MyController()
{
ControllerContext = mockContext
};

但是,如果您要使用 User 对象只是为了获取用户的 Id,则还有另一种方法适用于任何一种类型的 Controller ,并且需要的代码要少得多:

public class MyController: Controller //or ApiController
{
public Func<string> GetUserId; //For testing

public MyController()
{
GetUserId = () => User.Identity.GetUserId();
}
//controller actions
}

现在,当您需要用户 ID 时,无需调用 User.Identity.GetUserId(),您只需调用 GetUserId()。当您需要在测试中模拟用户 Id 时,您只需这样做:

controller = new MyController()
{
GetUserId = () => "IdOfYourChoosing"
};

这两种方法各有利弊。第一种方法更彻底、更灵活,并使用两种 Controller 类型上已经存在的接缝,但它的代码也多得多,而且阅读起来也不太好。第二种方法更简洁,IMO 更具表现力,但它是需要维护的额外代码,如果您不使用 Func 调用来获取用户 ID,您的测试将无法运行。选择更适合您情况的一种。

关于c# - 我如何模拟 User.Identity.GetUserId()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22762338/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com