模拟UserManager

4

I have the following code:

var clientId = this.UserManager.FindById(this.User.Identity.GetUserId()).ClientId;

这是我的应用程序中一个控制器的一部分。现在我正在编写单元测试,需要通过此功能以测试控制器的实际属性。

问题在于它会抛出空引用异常,因为 UserManager.FindById 返回 null。如果我可以模拟它,则它将具有一个名为ClientId的属性,我就能避免异常。

我尝试了什么? 首先是对UserManager本身进行模拟:

  var fakeUserManager = new Mock<ApplicationUserManager>();
  fakeUserManager.Setup(x => x.FindById(It.IsAny<string>()))
  .Returns(user);

但是当我尝试将controller.UserManager设置为它时:
controller.UserManager = fakeUserManager.Object;

Visual Studio提示UserManager无法在此上下文中使用,因为set访问器不可访问。

我决定使用UserManager创建用户,但create方法再次导致了空引用异常。

这是如何设置ApplicationUserManager的:

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

解决方案:

感谢@mason的回答,我成功解决了这个问题。我将把解决方案发布为编辑版本,因为解决方案中有些细节并没有在问题和答案中提到。 首先,如@mason所建议的那样,我将UserManager属性的setter设置为public。

public ApplicationUserManager UserManager
        {
            get
            {
                return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
            }

          set
            {
                _userManager = value;
            }
        }

其次,这是不同的部分。我能够通过模拟IUserStore,创建一个新的ApplicationUserManager并将用户传递给它:

var store = new Mock<IUserStore<User>>(MockBehavior.Strict);

            store.As<IUserStore<User>>()
            .Setup(x => x.FindByIdAsync(It.IsAny<string>()))
            .ReturnsAsync(user);

var manager = new ApplicationUserManager(store.Object);

然后,我只需设置控制器的UserManager:

controller.UserManager = manager;

备注: user变量帮助我向控制器传递具有ClientId的用户。


控制器中的UserManager属性最初是如何设置的?通过构造函数吗? - mason
1个回答

1
由于您将setter设置为私有,因此无法设置UserManager属性。请将其设置为公共。
public ApplicationUserManager UserManager
{
    get
    {
        return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
    }
    set
    {
        _userManager = value;
    }
}

现在您将能够设置控制器的UserManager属性。

非常好的回答,结合其他一些更改,我设法让它工作了,但我有几个问题。把store公开是好的吗?这是一个不好的习惯吗?会影响应用程序的安全性吗? - StefanL19
1
@StefanL19 "Public"和"private"是访问修饰符。它们不是安全功能,而是旨在帮助您构建一个只公开必要功能的库,以防止意外误用代码。这是一种组织上的考虑,而不是安全功能。 - mason

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接