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.

Amit Joshi
  • 15,448
  • 21
  • 77
  • 141
Yasser Shaikh
  • 46,934
  • 46
  • 204
  • 281

8 Answers8

47

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);
    }
}
tugberk
  • 57,477
  • 67
  • 243
  • 335
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

Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
11

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

controller.User = new ClaimsPrincipal(
  new GenericPrincipal(new GenericIdentity("user"), null));
jonnii
  • 28,019
  • 8
  • 80
  • 108
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

Community
  • 1
  • 1
pennstatephil
  • 1,593
  • 3
  • 22
  • 43
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;
Nikita
  • 300
  • 1
  • 2
  • 17
  • "Property or indexer 'ControllerBase.User' cannot be assigned to -- it is read only" – Fred Jun 04 '19 at 09:29
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;
            }
        }
Umapathy
  • 83
  • 11
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()
   {
   }
}
Daniel Bernsons
  • 650
  • 7
  • 20
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

Alexander
  • 1,152
  • 1
  • 16
  • 18