Comment puis-je me moquer de L'utilisateur.Identité.GetUserId()?

J'essaie de tester mon code unitaire qui inclut 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 was unhandled by user code". J'ai aussi 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 was unhandled by user code".

Toute aide quant à la façon dont je procède serait appréciée. Grâce.

28
demandé sur Patrick Quirk 2014-03-31 17:05:42

3 réponses

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

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
répondu Joe Taylor 2014-03-31 13:52:50

Vous ne pouvez pas simuler directement les méthodes d'extension, donc votre meilleur pari est de percer 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 posterais, mais la bibliothèque n'est pas actuellement open source, donc vous devrez 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, donc nous pouvons procédez comme 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"

Mise à jour: je viens de réaliser que la solution que j'ai postée ci-dessus ne fonctionne que pour ApiControllers dérivé (comme dans, API Web). La classe MVC Controller n'a pas de propriété settable User. Heureusement, il est assez facile de passer par les Controller ' s ControllerContext pour obtenir l'effet désiré:

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 l'objet User est d'obtenir L'Id 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'Id de l'utilisateur, vous appelez simplement GetUserId(). Lorsque vous devez vous moquer de l'Id utilisateur dans les tests, vous le faites simplement comme ceci:

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

Il y a des avantages et des inconvénients à ces deux approches. La première approche est plus approfondie et plus flexible et utilise des coutures 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 expressif, mais c'est un 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 fonctionne le mieux pour votre situation.

36
répondu joelmdev 2015-10-21 01:41:49

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

Maintenant, vous pouvez récupérer des valeurs à partir 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, il montre

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
répondu Haohmaru 2016-10-06 14:40:21