web-dev-qa-db-fra.com

Se moquer des nouveaux UserManager Identity Framework et RoleManager de Microsoft Entity Framework

Quelqu'un a-t-il trouvé une solution de simulation réussie pour UserManager et RoleManager? Je me suis cogné la tête contre un mur toute la journée. Tout ce que je veux faire, c'est se moquer des objets pour utiliser une collection en mémoire plutôt que de frapper le magasin de données Entity Framework. J'ai parcouru Internet et essayé plusieurs approches différentes en utilisant MOQ.

J'avais l'impression que les nouveaux trucs étaient beaucoup plus faciles à tester. Suis-je en train de manquer quelque chose?

43
Dale Alleshouse

Alternativement, vous pouvez vous moquer de l'interface IUserStore<TUser> Que UserManager accepte comme argument.

var userStore = new Mock<IUserStore<ApplicationUser>>();
var userManager = new UserManager(userStore.Object);

Comme le note @Joe Brunscheon dans le commentaire ci-dessous, UserManager détecte la prise en charge d'autres interfaces comme IUserPasswordStore, etc. Vous pouvez également les moq:

var passwordManager = userStore.As<IUserPasswordStore<ApplicationUser>>()
    .Setup(...).Returns(...);

Vous n'avez pas besoin de tout supprimer en même temps, vous pouvez simplement les moquer au besoin par votre code en cours de test. En réalité, le UserStore qu'EF utilise pour implémenter IUserStore implémente d'autres interfaces, et UserManager fera une détection interne pour voir si ces interfaces sont implémentées et, par conséquent, des fonctionnalités supplémentaires prises en charge. Heureusement, moq vous permet de simuler un substitut qui peut implémenter de nombreuses interfaces, en utilisant .As<T>().

En bref, Microsoft.AspNet.Identity vous donne tout ce dont vous avez besoin pour l'utiliser nu, sans wrapper, dans votre code. Tant que vous utilisez l'injection de dépendances pour instancier votre UserManager, vous pouvez le moq en toute sécurité dans les tests unitaires en simulant les interfaces qu'il consomme et en les passant via une sorte de moq IUserStore<T> Qui est augmenté pour prendre en charge les méthodes sur d'autres interfaces détecté en interne par UserManager.

37
danludwig

J'aime mettre à jour la solution à cette question pour tous ceux qui travaillent sur asp.net core:

    private Mock<UserManager<ApplicationUser>> GetMockUserManager()
    {
        var userStoreMock = new Mock<IUserStore<ApplicationUser>>();
        return new Mock<UserManager<ApplicationUser>>(
            userStoreMock.Object, null, null, null, null, null, null, null, null);
    }

Oui, 8 fois nul mais jusqu'à présent il n'y a pas de solution plus gracieuse. Si vous êtes intéressé par les autres paramètres, jetez un œil au code source .

25
rubito

Juste pour développer Rubito's réponse , voici comment je l'ai fait pour RoleManager:

public static Mock<RoleManager<ApplicationRole>> GetMockRoleManager()
{
   var roleStore = new Mock<IRoleStore<ApplicationRole>>();
   return new Mock<RoleManager<ApplicationRole>>(
                roleStore.Object,null,null,null,null);

}
2
jmdon
public class FakeUserManager : UserManager<User>
    {
        public FakeUserManager() 
            : base(new Mock<IUserStore<User>>().Object,
                  new Mock<IOptions<IdentityOptions>>().Object,
                  new Mock<IPasswordHasher<User>>().Object,
                  new IUserValidator<User>[0],
                  new IPasswordValidator<User>[0],
                  new Mock<ILookupNormalizer>().Object, 
                  new Mock<IdentityErrorDescriber>().Object,
                  new Mock<IServiceProvider>().Object,
                  new Mock<ILogger<UserManager<User>>>().Object, 
                  new Mock<IHttpContextAccessor>().Object)
        { }

        public override Task<User> FindByEmailAsync(string email)
        {
            return Task.FromResult(new User{Email = email});
        }

        public override Task<bool> IsEmailConfirmedAsync(User user)
        {
            return Task.FromResult(user.Email == "[email protected]");
        }

        public override Task<string> GeneratePasswordResetTokenAsync(User user)
        {
            return Task.FromResult("---------------");
        }
    }
2
valentasm

Vous ne pourrez pas simuler directement UserManager ou RoleManager. Ce que vous POUVEZ cependant faire, c'est se moquer d'un objet qui les utilise.

Par exemple:

public interface IWrapUserManager
{
    UserManager WrappedUserManager {get; set;}
    //provide methods / properties that wrap up all UserManager methods / props.
}

public class WrapUserManager : IWrapUserManager
{
    UserManager WrappedUserManager {get; set;}
    //implementation here. to test UserManager, just wrap all methods / props.
}

//Here's a class that's actually going to use it.
public class ClassToTest
{
    private IWrapUserManager _manager;
    public ClassToTest(IWrapUserManager manager)
    {
        _manager = manager;
    }
    //more implementation here
}

Passons à la moquerie:

[TestClass]
public class TestMock
{
    [TestMethod]
    public void TestMockingUserManager()
    {
        var mock = new Mock<IWrapUserManager>();
        //setup your mock with methods and return stuff here.
        var testClass = new ClassToTest(mock.Object); //you are now mocking your class that wraps up UserManager.
        //test your class with a mocked out UserManager here.
    }
}
2
Joe Brunscheon