42

I am writing test cases using the Unit Test for ASP.NET Web API.

Now I have an action which makes a call to some method I have defined in the service layer, where I have used the following line of code.

string username = User.Identity.Name; // do something with username // return something 

Now how to I create unit test method for this, I am getting null reference exceptions. I am kinda new to writing unit test and stuff.

I want to use Unit Test only for this. Please help me out on this.

1
  • are you trying to test the action method or the service layer method? Commented Oct 8, 2012 at 12:14

9 Answers 9

48

The below one is only one way of doing this:

public class FooController : ApiController { public string Get() { return User.Identity.Name; } } public class FooTest { [Fact] public void Foo() { var identity = new GenericIdentity("tugberk"); Thread.CurrentPrincipal = new GenericPrincipal(identity, null); var controller = new FooController(); Assert.Equal(controller.Get(), identity.Name); } } 
Sign up to request clarification or add additional context in comments.

4 Comments

It's an xUnit thing. Don't worry about it.
Its worth noting that this solution doesn't work for MVC controllers...only API controllers.
Only User.Identity.Name is working perfectly but not the method User.Identity.GetUserId()
@tugberk How to achive the same in mvc controller?
17

Here's another way I found in the NerdDinner testing tutorial. It worked in my case:

DinnersController CreateDinnersControllerAs(string userName) { var mock = new Mock<ControllerContext>(); mock.SetupGet(p => p.HttpContext.User.Identity.Name).Returns(userName); mock.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(true); var controller = CreateDinnersController(); controller.ControllerContext = mock.Object; return controller; } [TestMethod] public void EditAction_Should_Return_EditView_When_ValidOwner() { // Arrange var controller = CreateDinnersControllerAs("SomeUser"); // Act var result = controller.Edit(1) as ViewResult; // Assert Assert.IsInstanceOfType(result.ViewData.Model, typeof(DinnerFormViewModel)); } 

Make sure you read the full section: Mocking the User.Identity.Name property

It uses the Moq mocking framework that you can install in your Test project using NuGet: http://nuget.org/packages/moq

3 Comments

yes I have recently started using Moq for my new project, will surely consider this approach fr next time
I just wrote this answer because the accepted one did not work in my case. Don't know why... :)
If I'm not mistaken, this answer more applies to MVC than Web API. Might be why the accepted answer didn't work for you
12

With WebApi 5.0 this is slightly different. You can now do:

controller.User = new ClaimsPrincipal( new GenericPrincipal(new GenericIdentity("user"), null)); 

1 Comment

I'm looking at v5.2.0.0 of Controller in System.Web.Mvc.dll, and IPrincipal User only has a get, no set...
1

None of this ended up working for me, I used the solution on another question which uses Moq to set up a user name in the ControllerContext: https://stackoverflow.com/a/6752924/347455

Comments

1

This is my solution.

var claims = new List<Claim> { new Claim(ClaimTypes.Name, "Nikita"), new Claim(ClaimTypes.NameIdentifier, "1") }; var identity = new ClaimsIdentity(claims); IPrincipal user = new ClaimsPrincipal(identity); controller.User = user; 

1 Comment

"Property or indexer 'ControllerBase.User' cannot be assigned to -- it is read only"
0

Here i found the solution for another way that how to set the user identity name for the controller level testing from the test method.

public static void SetUserIdentityName(string userId) { IPrincipal principal = null; principal = new GenericPrincipal(new GenericIdentity(userId), new string[0]); Thread.CurrentPrincipal = principal; if (HttpContext.Current != null) { HttpContext.Current.User = principal; } } 

Comments

0

When I run Unit test - in my case it uses Windows authentication and Identity.Name is my domain name, which I also want to change for the test. So I use such approach with 'hacking' things I want in IAuthenticationFilter

Comments

0

If you have lots of Controllers to Test then I Would Suggest to create a base class and in the constructor create a GenericIdentity & GenericPrincipal and set Thread.CurrentPrincipal

GenericPrincipal principal = new GenericPrincipal(new GenericIdentity("UserName"),null); Thread.CurrentPrincipal = principal; 

Then Inherit that class .. So that way every Unit Test class will have Principle Object Set

[TestClass] public class BaseUnitTest { public BaseUnitTest() { GenericPrincipal principal = new GenericPrincipal(new GenericIdentity("UserName"),null); Thread.CurrentPrincipal = principal; } } [TestClass] public class AdminUnitTest : BaseUnitTest { [TestMethod] public void Admin_Application_GetAppliction() { } } 

Comments

0

Not sure if AspNetCore changed a lot, but nowadays in Net7 you can simply do this

someController.ControllerContext.HttpContext = new DefaultHttpContext { User = new GenericPrincipal(new GenericIdentity(userName) , new []{string.Empty}) }; 

An example with a working unit test

 [Test] public async Task GetAll_WhenUserNotExist_ReturnsNotFound() { // arrange var autoMock = AutoMock.GetLoose(); const string userName = "[email protected]"; var customersServiceMock = autoMock.Mock<ICustomerService>(); customersServiceMock .Setup(service => service.GetAll(userName)).Throws<UserDoesNotExistException>(); var customerController = autoMock.Create<CustomerController>(); // // Create a new DefaultHttpContext and assign a generic identity which you can give a user name customerController.ControllerContext.HttpContext = new DefaultHttpContext { User = new GenericPrincipal(new GenericIdentity(userName) , new []{string.Empty}) }; var httpResult = await customerController.GetAllCustomers() as NotFoundResult; // act Assert.IsNotNull(httpResult); } 

The implementation of the controller

 [HttpGet] [Route("all")] public async Task<IActionResult> GetAllCustomers() { // User identity name will return harry@potter now. var userName = User.Identity?.Name; try { var customers = await _customerService.GetAll(userName).ConfigureAwait(false); return Ok(customers); } catch (UserDoesNotExistException) { Log.Warn($"User {userName} does not exist"); return NotFound(); } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.