Reputation: 193
I would like to know if someone can help me with this.
I am writing unit tests for a specific controller. That controller inherits from a BaseController and that BaseController has this property:
private ApplicationUserManager userManager;
public ApplicationUserManager UserManager
{
get { return this.userManager ?? this.Request.GetOwinContext().GetUserManager<ApplicationUserManager>(); }
set { this.userManager = value; }
}
The ctor for ApplicationUserManager is:
public ApplicationUserManager(IUserStore<ApplicationUser> store, IIdentityMessageService emailService)
: base(store)
{
this.EmailService = emailService;
var dataProtectionProvider = Startup.DataProtectionProvider;
this.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
This is what I am doing to mock the ApplicatonUserManager class:
var store = new Mock<IUserStore<ApplicationUser>>();
var emailService = new Mock<IIdentityMessageService>();
var applicationUserManager = new Mock<ApplicationUserManager>(store.Object, emailService.Object);
this.targetController.UserManager = applicationUserManager.Object;
var dataprotectionprovided = new Mock<IDataProtectionProvider>();
applicationUserManager.Setup(r => r.UserTokenProvider).Returns(new DataProtectorTokenProvider<ApplicationUser, string>(dataprotectionprovided.Object.Create("ASP.NET Identity")));
this.targetController.UserManager = applicationUserManager.Object;
I have tried to mock this but because this is not virtual property (UserTokenProvider) it does not allow me and I get this exception:
System.NotSupportedException: Invalid setup on a non-virtual (overridable in VB) member: r => r.UserTokenProvider
Can anyone help me with this problem? I just want to mock this in order to test the controller that inherits from a BaseController that has that property..
Thanks
Upvotes: 0
Views: 2075
Reputation: 388
As pointed out in one of the comments in your answer, creating an additional constructor could lead to another developer using the wrong one.
Can I suggest that instead of this you try the following.
Move the code inside of your original ApplicationUserManager constructor, into a new protected virtual method. Then amend the now empty constructor to call new virtual method.
public class ApplicationUserManager
{
public ApplicationUserManager(IUserStore<ApplicationUser> store, IIdentityMessageService emailService)
: base(store)
{
CalledAfterConstruction();
}
protected virtual void CalledAfterConstruction()
{
this.EmailService = emailService;
var dataProtectionProvider = Startup.DataProtectionProvider;
this.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
}
Now create a new MockApplicationUserManager class when unit testing that inherits ApplicationUserManager, override the inherited 'CalledAfterConstruction' with just a empty method and you pretty much have things the way you did in your answer.
public class MockClass : ApplicationUserManager
{
public MockClass(IUserStore<ApplicationUser> store, IIdentityMessageService emailService) : base(store, emailService)
{
}
protected override void CalledAfterContruction()
{
}
}
Yes this is a little more complicated but it does stop people from misusing your original class
Upvotes: 0
Reputation: 193
Thanks for your help @bwyn
I have managed to crack it with your suggestion. Just created a new constructor for the ApplicationUserManager like this:
public ApplicationUserManager(IUserStore<ApplicationUser> store) : base(store)
{
}
And then the Unit Testing :
var user = new ApplicationUser { User = new User { UserId = 1 } };
var store = new Mock<IUserStore<ApplicationUser>>(MockBehavior.Strict);
store.As<IUserStore<ApplicationUser>>().Setup(x => x.FindByIdAsync(It.IsAny<string>())).ReturnsAsync(user);
this.targetController.UserManager = new ApplicationUserManager(store.Object);
Thank you all!
Upvotes: 1