如何模拟HttpContext.User

Edm*_*ooi 6 c# asp.net-mvc unit-testing moq httpcontext

我正在开发一个Asp.net MVC 5项目,我正在尝试设置一个模拟以在控制器中返回自定义主体.我有搜索并尝试了不同的方法,但没有一个有效.

我有一个BaseController,我的所有控制器都继承自.BaseController有一个User属性,它在getter中返回HttpContext.User.HttpContext.user在项目中调用时返回一个值,但在从单元测试项目调用时返回null.

BaseController

public class BaseController : Controller
{
    protected virtual new CustomPrincipal User
    {
        get { return HttpContext.User as CustomPrincipal; }  ***<== Line with issue***
    }
}
Run Code Online (Sandbox Code Playgroud)

自定义校长

public class CustomPrincipal : IPrincipal, ICustomPrincipal
{
    public IIdentity Identity { get; private set; }

    public string UserId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public bool   IsStoreUser { get; set; }

    public CustomPrincipal(string username)
    {
        this.Identity = new GenericIdentity(username);
    }
}
Run Code Online (Sandbox Code Playgroud)

调节器

public class DocumentsController : BaseController
    {
        public ViewResult ViewDocuments()
        {
            var userType = User.IsStoreUser ? UserType.StoreUser : UserType.Corporate;  ***<== User is null when calling from a unit test.***
        }
    }
Run Code Online (Sandbox Code Playgroud)

测试用例

[Test]
public void ViewDocuments_WhenCalled_ShouldReturnViewModel()
{
    // Arrange
    var principal = new CustomPrincipal("2038786");
    principal.UserId = "2038786";
    principal.FirstName = "Test";
    principal.LastName = "User";
    principal.IsStoreUser = true;

    var _mockController = new Mock<DocumentsController>(new UnitOfWork(_context)) { CallBase = true };
        _mockController.Setup(u => u.User).Returns(principal);  ***<== Error - "Invalid setup on a non-virtual (overridable in VB) member: u => u.User"***

    // Act
    var result = _controller.ViewDocuments();
}
Run Code Online (Sandbox Code Playgroud)

我正在使用nUnit和Moq来创建模拟对象,但我不确定我做错了什么.我需要在DocumentControl中模拟User.IsStore的返回,以在我在测试中创建的自定义主体对象中返回IsStore的值.

Nko*_*osi 7

制作模拟http上下文

private class MockHttpContext : HttpContextBase {
    private readonly IPrincipal user;

    public MockHttpContext(IPrincipal principal) {
        this.user = principal;
    }

    public override IPrincipal User {
        get {
            return user;
        }
        set {
            base.User = value;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

相应地安排测试。

[Test]
public void ViewDocuments_WhenCalled_ShouldReturnViewModel() {
    // Arrange
    var principal = new CustomPrincipal("2038786");
    principal.UserId = "2038786";
    principal.FirstName = "Test";
    principal.LastName = "User";
    principal.IsStoreUser = true;

    var mockUoW = new Mock<IUnitOfWork>();
    //...setup UoW dependency if needed
    var controller = new DocumentsController(mockUoW.Object);
    controller.ControllerContext = new ControllerContext {
        Controller = controller,
        HttpContext = new MockHttpContext(principal)
    };

    // Act
    var result = controller.ViewDocuments();

    //Assert
    //...assertions
}
Run Code Online (Sandbox Code Playgroud)

不要嘲笑正在测试的系统。模拟其依赖项。


use*_*702 6

如果你不HttpContext直接依赖的话,事情会变得容易得多。创建一个IUserProvider接口和一个依赖于HttpContext(例如)的实现,然后在测试中HttpContextUserProvider存根。IUserProvider

IUserProvider通过依赖项注入传递到您的控制器。