web-dev-qa-db-fra.com

Comment se moquer de User.Identity.GetUserId ()?

J'essaie de tester mon code unitaire qui comprend la ligne:

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

Je suis juste coincé sur un bit car je ne peux pas obtenir:

User.Identity.GetUserId()

pour renvoyer une valeur. J'ai essayé ce qui suit dans la configuration de mon contrôleur:

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

Mais cela donne une erreur de "NotSupportedException a été gérée par le code utilisateur". J'ai également essayé ce qui suit:

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;

Basé sur du code que j'ai trouvé sur stackoverflow, mais cela renvoie la même erreur "NotSupportedException a été gérée par le code utilisateur".

Toute aide sur la façon dont je procède serait appréciée. Merci.

31
AndrewPolland

Vous ne pouvez pas configurer la méthode GetUserId car c'est une méthode d'extension. À la place, vous devrez configurer le nom sur la propriété IIdentity de l'utilisateur. GetUserId l'utilisera pour déterminer l'UserId.

var context = new Mock<HttpContextBase>();
var mockIdentity = new Mock<IIdentity>();
context.SetupGet(x => x.User.Identity).Returns(mockIdentity.Object);
mockIdentity.Setup(x => x.Name).Returns("test_name");

Voir ceci pour plus d'informations: http://msdn.Microsoft.com/en-us/library/Microsoft.aspnet.identity.identityextensions.getuserid (v = vs.111) .aspx

20
Joe Taylor

Vous ne pouvez pas vous moquer directement des méthodes d'extension, donc votre meilleur pari est de descendre jusqu'à ce que vous atteigniez les propriétés et les méthodes dont dépend la méthode d'extension qui sont moquables.

Dans ce cas, IIdentity.GetuUserId() est une méthode d'extension. Je le publierais, mais la bibliothèque n'est pas actuellement open source, vous devrez donc voir par vous-même que GetUserId() dépend de ClaimsIdentity.FindFirstValue(). Il s'avère que c'est aussi une méthode d'extension, mais cela dépend de ClaimsIdentity.FindFirst(), qui est marqué virtual. Maintenant, nous avons notre couture, nous pouvons donc faire ce qui suit:

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"

pdate: Je viens de réaliser que la solution que j'ai postée ci-dessus ne fonctionne que pour les ApiControllers dérivés (comme dans, Web API). La classe MVC Controller n'a pas de propriété User réglable. Heureusement, il est assez facile d'entrer dans les ControllerControllerContext pour obtenir l'effet souhaité:

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

Cependant, si tout ce que vous allez utiliser pour l'objet User est d'obtenir l'identifiant de l'utilisateur, il existe une autre approche qui fonctionnera pour l'un ou l'autre type de contrôleur et nécessite beaucoup moins de code:

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

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

Maintenant, au lieu d'appeler User.Identity.GetUserId() lorsque vous voulez l'identifiant de l'utilisateur, vous appelez simplement GetUserId(). Lorsque vous devez simuler l'ID utilisateur dans les tests, vous le faites simplement comme ceci:

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

Les deux approches présentent des avantages et des inconvénients. La première approche est plus approfondie et plus flexible et utilise des coutures qui sont déjà présentes sur les deux types de contrôleurs, mais c'est aussi beaucoup plus de code et ne lit pas aussi bien. La deuxième approche est beaucoup plus propre et IMO plus expressive, mais c'est du code supplémentaire à maintenir, et si vous n'utilisez pas l'appel Func pour obtenir l'ID de l'utilisateur, vos tests ne fonctionneront pas. Choisissez celui qui convient le mieux à votre situation.

37
joelmdev

Cela a fonctionné pour moi

en utilisant fakeiteasy

        var identity = new GenericIdentity("TestUsername");
        identity.AddClaim(new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", "UserIdIWantReturned"));

        var fakePrincipal = A.Fake<IPrincipal>();
        A.CallTo(() => fakePrincipal.Identity).Returns(identity);

        var _controller = new MyController
        {
            ControllerContext = A.Fake<ControllerContext>()
        };

        A.CallTo(() => _controller.ControllerContext.HttpContext.User).Returns(fakePrincipal); 

Vous pouvez maintenant récupérer les valeurs de ces méthodes d'extension IIdentity:

par exemple.

        var userid = _controller.User.Identity.GetUserId();
        var userName = _controller.User.Identity.GetUserName();

Lors de l'affichage de la méthode GetUserId () avec ILSpy, elle affiche

public static string GetUserId(this IIdentity identity)
{
  if (identity == null)
  {
    throw new ArgumentNullException("identity");
  }
  ClaimsIdentity claimsIdentity = identity as ClaimsIdentity;
  if (claimsIdentity != null)
  {
    return claimsIdentity.FindFirstValue(http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier);
  }
  return null;
}

GetUserId a donc besoin de la revendication " nameidentifier "

4
Haohmaru