使用 Windows 身份验证在 WebAPI 控制器上进行单元测试
UnitTest on WebAPI controller with Windows Authentication
我有一个 api,里面的方法很少。在访问任何控制器方法之前,我需要使用 Windows Authentication
对用户进行身份验证。为此,我编写了一个私有方法来获取 UserIdentity
并将其分配给私有 bool
变量。
每个控制器方法都会首先检查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 }
}
}
单元测试结果总是return 401.
在 run-time 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
//...
}
我有一个 api,里面的方法很少。在访问任何控制器方法之前,我需要使用 Windows Authentication
对用户进行身份验证。为此,我编写了一个私有方法来获取 UserIdentity
并将其分配给私有 bool
变量。
每个控制器方法都会首先检查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 }
}
}
单元测试结果总是return 401.
在 run-time 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
//...
}