49

Has anyone come up with a successful mocking solution for UserManager and RoleManager? I have been beating my head against a wall all day. All I want to do is mock the objects to use an in memory collection rather than hitting the Entity Framework data store. I've scoured the internet and tried several different approaches using MOQ.

I was under the impression that the new stuff was much easier to test. Am I missing something?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Dale Alleshouse
  • 1,627
  • 2
  • 17
  • 24
  • just googled arround and found your question on another website: https://codedump.io/share/4gbVkWtXFw9M/1/mocking-new-microsoft-entity-framework-identity-usermanager-and-rolemanager funny how the answer is copied from here lol – Moritz Schmidt May 04 '17 at 09:49
  • very useful article https://alastairchristian.com/mocking-asp-net-identity-2-usermanager-methods-b740c703b580 – Simon_Weaver Dec 29 '18 at 02:26

6 Answers6

41

Alternatively, you can mock the IUserStore<TUser> interface that UserManager accepts as an argument.

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

As @Joe Brunscheon notes in the comment below, UserManager detects support for other interfaces like IUserPasswordStore, etc. You can also moq those:

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

You don't have to moq out all of these at once, you can just moq them up as needed by your code-under-test. In reality, the UserStore that EF uses to implement IUserStore implements other interfaces, and UserManager will do internal detection to see if these interfaces are implemented, and therefore, additional features supported. Fortunately, moq lets you mock up a surrogate that can implement many interfaces, using .As<T>().

In short, Microsoft.AspNet.Identity does give you everything you need to use it bare, without a wrapper, in your code. As long as you use dependency injection to instantiate your UserManager, you can safely moq it in unit tests by mocking up the interfaces it consumes and passing them via some kind of IUserStore<T> moq that is augmented to support methods on other interfaces internally detected by UserManager.

ono2012
  • 4,967
  • 2
  • 33
  • 42
danludwig
  • 46,965
  • 25
  • 159
  • 237
  • IUserStore doesn't provide all the functionality of UserManager. The basics are there, but there is a lot more in UserManager that would likely need to be mocked out in order to get good test coverage over classes that use UserManager. – Joe Brunscheon Jan 17 '14 at 20:04
  • Thank you for your quick reply. I decided to try to use a fake rather than trying to Mock. I created a new instance of 'IdentityDbContext' using an in memory DbSet and passed that into the 'IUserStore' constructor. For some reason, it acts as if my DbSets are always empty. I verified that I can query users and roles directly from the IdentityDbContext object. I wonder if this should be a separate question... – Dale Alleshouse Jan 17 '14 at 22:23
  • I stumbled upon this same question . However mocking with IUserStore with DbContext and then passing it to UserManager Seems too much work . So I straight used DI container to get 'MyUserManager' . In that manner the object graph testability is guarenteed via `container.verify()` method . So that If any of the dependency graph for asp.net identity breaks , the test would fail as `container.verify()` would throw exception – Joy Dec 10 '14 at 15:43
  • @Joy that is definitely one way you can do it, but that is technically not a unit test, it is an integration test. You are testing the integration of the IUserStore with your IoC container. – danludwig Dec 10 '14 at 16:08
  • @danludwig So you mean if we need to unit test . We need to mock or fake each and every single object of the object graph ? So just to test `UserManager.CreateAsync()` or `UserManager.DeleteAsync()` method ? After all I am testing only one single responsibility for my business logic . Does it realy pay off to mock all the dependencies explicitly for single class instead of using DI container ? Just to test one single functionality ? – Joy Dec 10 '14 at 16:26
  • 1
    @Joy You shouldn't need to fake / mock each and every object in the dependency graph, only those that are used by the Method Under Test. "Does it really pay off" is a subjective question... how much revenue does the app generate, the volatility of your customers & market, and the payroll of your developers will help answer that question. Also I am not saying that integration tests are bad and you should do unit tests instead. I was just pointing out the difference. In reality, you should have both unit tests and integration tests, as well as user acceptance tests (if the are worth having). – danludwig Dec 10 '14 at 16:53
  • There is a small issue with this answer which is that you need to add the generic type when instantiating the UserManager class e.g. new UserManager(); – mbrookson Jun 17 '19 at 16:18
34

I like to update the solution to this question for anyone who works on 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);
    }

Yes, 8 times null but so far there isn't any more graceful solution. If you are interested on the other parameters, take a look at the source code.

Padhraic
  • 5,112
  • 4
  • 30
  • 39
rubito
  • 471
  • 6
  • 5
  • Does this still work? Visual Studio doesnt know ApplicationUser in my case – Moritz Schmidt Apr 26 '17 at 05:32
  • 2
    ApplicationUser is created by the asp.net core project template. If you aren't using that template, then try out 'IdentityUser' since that is the root class from which ApplicationUser inherits from. – rubito Apr 26 '17 at 22:24
  • 1
    Is it possible to Mock a useful UserStore? It seem's really hard to mock a working DbContext class.. Any experience with that? :-) – Moritz Schmidt May 04 '17 at 13:53
  • 1
    @MoritzSchmidt sorry for the necro, but define an interface that your DbContext implements and mock that instead. Then the hard part is mocking the DbSets properly, but you can get most of that functionality pretty easily: https://www.jankowskimichal.pl/en/2016/01/mocking-dbcontext-and-dbset-with-moq/#Method%20with%20LINQ – Marshall Tigerus Apr 13 '18 at 17:11
4

You won't be able to Mock UserManager or RoleManager directly. What you CAN do, however, is mock an object that uses them.

For Example:

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
}

On to the mocking:

[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.
    }
}
Joe Brunscheon
  • 1,949
  • 20
  • 21
4

Just to expand on Rubito's answer, here is how I did it for RoleManager:

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

}
jmdon
  • 997
  • 9
  • 17
3
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 == "test@test.com");
        }

        public override Task<string> GeneratePasswordResetTokenAsync(User user)
        {
            return Task.FromResult("---------------");
        }
    }
valentasm
  • 2,137
  • 23
  • 24
  • to take this one step further (and easier) you can define an IUserManager interface yourself, create an empty subclass that implements it and replace your references to UserManager with the interface. – Marshall Tigerus Apr 13 '18 at 17:13
2

Here is an explicit version of Rubito's excellent answer for NET Core 3.1 without the null, null, nulls:

public static UserManager<TUser> GetUserManager<TUser>(IUserStore<TUser> store = null) 
    where TUser : class
{
    // https://github.com/aspnet/Identity/blob/master/test/Shared/MockHelpers.cs
    store = store ?? new Mock<IUserStore<TUser>>().Object;
    var options = new Mock<IOptions<IdentityOptions>>();
    var idOptions = new IdentityOptions();
    idOptions.Lockout.AllowedForNewUsers = false;
    options.Setup(o => o.Value).Returns(idOptions);
    var userValidators = new List<IUserValidator<TUser>>();
    var validator = new Mock<IUserValidator<TUser>>();
    userValidators.Add(validator.Object);
    var pwdValidators = new List<PasswordValidator<TUser>>();
    pwdValidators.Add(new PasswordValidator<TUser>());
    var userManager = new UserManager<TUser>(
        store: store, 
        optionsAccessor: options.Object, 
        passwordHasher: new PasswordHasher<TUser>(),
        userValidators: userValidators,
        passwordValidators: pwdValidators, 
        keyNormalizer: new UpperInvariantLookupNormalizer(),
        errors: new IdentityErrorDescriber(), 
        services: null,
        logger: new Mock<ILogger<UserManager<TUser>>>().Object);
    validator.Setup(v => v.ValidateAsync(userManager, It.IsAny<TUser>()))
        .Returns(Task.FromResult(IdentityResult.Success)).Verifiable();
    return userManager;
}
Cesar
  • 2,059
  • 25
  • 30