Mocking new Microsoft Entity Framework Identity UserManager and RoleManager
Solution 1
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.
Solution 2
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.
Solution 3
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);
}
Solution 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.
}
}
Solution 5
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("---------------");
}
}
Related videos on Youtube
Dale Alleshouse
Updated on July 09, 2022Comments
-
Dale Alleshouse almost 2 years
Has anyone come up with a successful mocking solution for
UserManager
andRoleManager
? 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?
-
Moritz Schmidt almost 7 yearsjust googled arround and found your question on another website: codedump.io/share/4gbVkWtXFw9M/1/… funny how the answer is copied from here lol
-
aruno over 5 yearsvery useful article alastairchristian.com/…
-
-
Joe Brunscheon over 10 yearsIUserStore 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.
-
Dale Alleshouse over 10 yearsThank 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<ApplicationUser>' 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...
-
Joy over 9 yearsI stumbled upon this same question . However mocking with IUserStore<T> 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 ascontainer.verify()
would throw exception -
danludwig over 9 years@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.
-
Joy over 9 years@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()
orUserManager.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 ? -
danludwig over 9 years@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).
-
Moritz Schmidt about 7 yearsDoes this still work? Visual Studio doesnt know ApplicationUser in my case
-
rubito about 7 yearsApplicationUser 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.
-
Moritz Schmidt almost 7 yearsIs it possible to Mock a useful UserStore? It seem's really hard to mock a working DbContext class.. Any experience with that? :-)
-
Marshall Tigerus about 6 years@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: jankowskimichal.pl/en/2016/01/…
-
Marshall Tigerus about 6 yearsto 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.
-
mbrookson almost 5 yearsThere 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<ApplicationUser>();