具有Windows身份验证的WebAPI控制器上的UnitTest

时间:2019-05-29 10:38:56

标签: c# unit-testing asp.net-web-api asp.net-web-api2

我有一个方法很少的api。我需要先通过Windows Authentication对用户进行身份验证,然后才能访问任何控制器方法。为此,我编写了一个私有方法来获取UserIdentity并将其分配给私有bool变量。

每种控制器方法都将首先检查布尔值以验证用户,如果失败,则会将401返回前端。

在将单元测试用例写入控制器方法的同时,我不确定如何模拟UserIdentity还是应该以允许测试UserIdentity的方式更新控制器

控制器:

public class DefaultController : ApiController
{
  private bool isUsrAuthenticated;

  public DefaultController()
  {
    AuthenticateUser();
  }

  private void AuthenticateUser()
  {
    isUsrAuthenticated = User.Identity.IsAuthenticated;
  }

  [HttpGet]
  public IHttpActionResult GetProducts()
  {
    if (isUsrAuthenticated) { // do something }
    else { // throw 401 }
  }

  [HttpPost]
  public IHttpActionResult Update()
  {
    if (isUsrAuthenticated) { // do something }
    else { // throw 401 }
  }
}

单元测试结果始终返回401。

1 个答案:

答案 0 :(得分:0)

在运行时,调用控制器的构造函数后,将ApiController.User属性设置得很好。这意味着您当前在构造器中调用它的流程就像

public DefaultController() {
    AuthenticateUser();
}

存在缺陷,无法提供预期的行为。

让我们先修复代码,然后查看单元测试。

使用类似的属性

private bool IsUserAuthenticated {
    get {
        return User.Identity.IsAuthenticated;
    }
}

并相应地重构代码

public class DefaultController : ApiController {

    private bool IsUserAuthenticated {
        get {
            return User.Identity.IsAuthenticated;
        }
    }

    [HttpGet]
    public IHttpActionResult GetProducts() {
        if (IsUserAuthenticated) { // do something }
        else { // throw 401 }
    }

    [HttpPost]
    public IHttpActionResult Update() {
        if (IsUserAuthenticated) { // do something }
        else { // throw 401 }
    }

    //...

}

现在,为了测试ApiController,可以在安排单元测试时设置User属性,以使测试按预期进行

例如

[TestMethod()]
public void DefaultController_Should_GetProducts() {
    //Arrange
    var username = "name_here";
    var userId = 2;

    var identity = new GenericIdentity(username, "");
    identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userId.ToString()));
    identity.AddClaim(new Claim(ClaimTypes.Name, username));

    var principal = new GenericPrincipal(identity, roles: new string[] { });
    var user = new ClaimsPrincipal(principal);

    var controller = new DefaultController() {
        User = user //<-- Set the User on the controller directly
    };

    //Act
    var actionResult = controller.GetProducts();

    //Assert
    //...
}