在ASP.NETWeb API中为使用User.Identity.Name的方法编写单元测试

dzhpxtsq  于 8个月前  发布在  .NET
关注(0)|答案(9)|浏览(86)

我正在使用ASP.NET Web API的单元测试编写测试用例。
现在我有了一个动作,它调用了我在服务层中定义的某个方法,我在其中使用了以下代码行。

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

现在我如何创建单元测试方法,我得到空引用异常。我对编写单元测试之类的东西还比较陌生。
我只想使用单元测试来实现这一点。请帮我这个忙。

a0x5cqrl

a0x5cqrl1#

下面的一个只是这样做的一种方式:

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

xpszyzbs2#

下面是我在NerdDinner测试教程中发现的另一种方法。它在我的情况下工作:

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

请确保您阅读完整部分:Mocking the User.Identity.Name property
它使用Moq mocking框架,您可以使用NuGet安装在Test project中:http://nuget.org/packages/moq

tjvv9vkg

tjvv9vkg3#

在WebApi 5.0中,这一点略有不同。您现在可以:

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

vxbzzdmp4#

这些都没有对我起作用,我在另一个问题上使用了这个解决方案,它使用Moq在ControllerContext中设置用户名:https://stackoverflow.com/a/6752924/347455

uyto3xhc

uyto3xhc5#

这是我的解决方案。

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

ru9i0ody6#

在这里我找到了另一种方法的解决方案,即如何从测试方法中为控制器级别的测试设置用户标识名。

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

r55awzrz7#

当我运行单元测试时-在我的情况下,它使用Windows身份验证和Identity。Name是我的域名,我也想为测试更改。所以我用such approach with 'hacking' things I want in IAuthenticationFilter

dl5txlt9

dl5txlt98#

如果你有很多控制器要测试,那么我建议你创建一个基类,在构造函数中创建一个GenericIdentityGenericPrincipal,并设置Thread.CurrentPrincipal

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

继承这个类。这样,每个单元测试类都将具有Principle对象集

[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()
   {
   }
}
50few1ms

50few1ms9#

不知道AspNetCore是否改变了很多,但现在在Net7中,你可以简单地做到这一点

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

一个工作单元测试的例子

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

控制器的实现

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

相关问题