简体   繁体   English

模拟ApplicationUserManager用于单元测试MVC控制器

[英]Mock ApplicationUserManager for Unit Testing MVC controllers

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: 该控制器继承自BaseController,该BaseController具有以下属性:

private ApplicationUserManager userManager;
public ApplicationUserManager UserManager 
{ 
    get { return this.userManager ??  this.Request.GetOwinContext().GetUserManager<ApplicationUserManager>(); } 
    set { this.userManager = value; } 
}

The ctor for ApplicationUserManager is: ApplicationUserManager的ctor为:

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: 这是我要模拟ApplicatonUserManager类的操作:

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: 我试图模拟这个,但是因为这不是虚拟属性(UserTokenProvider),所以它不允许我出现此异常:

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.. 我只想对此进行模拟,以测试从具有该属性的BaseController继承的控制器。

Thanks 谢谢

Thanks for your help @bwyn 感谢您的帮助@bwyn

I have managed to crack it with your suggestion. 我已经设法通过你的建议。 Just created a new constructor for the ApplicationUserManager like this: 刚刚为ApplicationUserManager创建了一个新的构造函数,如下所示:

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! 谢谢你们!

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. 将原始ApplicationUserManager构造函数内部的代码移动到新的受保护的虚拟方法中。 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. 现在,在单元测试时创建一个新的MockApplicationUserManager类,该类继承了ApplicationUserManager,仅使用一个空方法覆盖了继承的“ CalledAfterConstruction”,您几乎可以像在答案中那样做。

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 是的,这有点复杂,但这确实阻止了人们滥用您的原始课程

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM