20

I am working on a Asp.net MVC 5 project and I am trying to setup a mock to return a custom principal within a controller. I have search and tried different approach suggested but none of them works.

I have a BaseController which all my controllers inherit from. The BaseController has a User property which return HttpContext.User in the getter. The HttpContext.user returns a value when called within the project but return a null when call from a unit test project.

BaseController

public class BaseController : Controller { protected virtual new CustomPrincipal User { get { return HttpContext.User as CustomPrincipal; } ***<== Line with issue*** } } 

Custom Principal

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); } } 

Controller

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

Test Case

[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(); } 

I'm using nUnit and Moq to create the mock object but I not sure what I'm doing wrong. I need to mock the return of User.IsStore in the DocumentControl to return the value of IsStore in the custom principal object i created in the test.

2 Answers 2

20

Make a mock http context

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; } } } 

Arrange test accordingly.

[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 } 

Don't mock system under test. Mock its dependencies.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks Nkosi, this works great. Thanks for your help and suggestions.
@Nkosi Could you please take a look at this question: stackoverflow.com/questions/77647669/…
This is a good answer. In my case I did not have a CustomPrincipal class, but found I was able to use new ClaimsPrincipal.
6

It gets a lot easier if you don't depend on HttpContext directly. Create an IUserProvider interface and an implementation that depends on HttpContext (e.g. HttpContextUserProvider), then stub the IUserProvider in your tests.

The IUserProvider should be passed along to your controller via dependency injection.

3 Comments

Stijn, thanks for your response to my question. Do you have an example of what you are suggesting. I am always interested in simplifying/refactoring my code where possible. Thanks.
@EdmandLooi I'll try to include an example later this week. In case I forget, feel free to ping me again in a week or so :)
From the Microsoft Documentation: how to add HttpContext via Dependency Injection learn.microsoft.com/en-us/aspnet/core/fundamentals/…

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.