C# 单元测试已获得JWT授权的Web API控制器
我试图在WebAPI控制器下面进行单元测试C# 单元测试已获得JWT授权的Web API控制器,c#,unit-testing,asp.net-web-api,authorization,moq,C#,Unit Testing,Asp.net Web Api,Authorization,Moq,我试图在WebAPI控制器下面进行单元测试 [IdentityBasicAuthentication] [Authorize] [HttpPost] public HttpResponseMessage GetOrderByQR([FromBody]string id) { try { var identity = HttpContext.Current.User.Identity as Claims
[IdentityBasicAuthentication]
[Authorize]
[HttpPost]
public HttpResponseMessage GetOrderByQR([FromBody]string id)
{
try
{
var identity = HttpContext.Current.User.Identity as ClaimsIdentity;
var user = UserManager().IdentifyToken(identity);
_orderManager.CheckOrderQRFraud(id);
return Request.CreateResponse(HttpStatusCode.OK, _orderManager.GetSingleOrderWithUserPaymentAccountBy(user.UserID, id));
}
catch (BusinessException ex)
{
return CreateRawStringResponse(HttpStatusCode.NotFound, ex.Message);
}
}
但下面的测试方法在IdentifyToken上抛出null异常,因为并没有当前用户,我理解这一点
[TestMethod]
public void GetOrderByQR_Returns_OK_On_Successful_Request()
{
string orderID = "4B854B3D-397E-425F-AEAF-00F7B4110021";
var testResponse = _orderController.GetOrderByQR(orderID);
Assert.AreEqual(HttpStatusCode.OK, testResponse.StatusCode);
}
当我在搜索答案时,我发现解决方案在于模拟这个授权属性。所以,尽管我安装了这个软件包,但我还是无法像刚开始单元测试一样成功地运行测试
下面是IdentityToken方法,如果您还需要检查它
public User IdentifyToken(ClaimsIdentity identity)
{
string userEmail = "";
string userPassword = "";
if (identity != null)
{
IEnumerable<Claim> claims = identity.Claims;
List<Claim> claimsArray = claims.ToList();
string[] emailArray = claimsArray[0].ToString().Split(':');
string emailValue = emailArray[2].ToString();
userEmail = emailValue.Trim();
string[] passwordArray = claimsArray[1].ToString().Split(':');
string passwordValue = passwordArray[2].ToString();
userPassword = passwordValue.Trim();
}
var user = base.GetSingleBy(x => x.Email == userEmail && x.Password == userPassword);
return user;
}
您可以使用TestServer来测试API方法
using (var server = TestServer.Create<Startup>())
{
var result = await server.HttpClient.GetAsync("api/Orders/id");
string responseContent = await result.Content.ReadAsStringAsync();
var entity = JsonConvert.DeserializeObject<List<Orders>>(responseContent);
// other code
}
在花了一天的时间学习更多关于单元测试的知识之后,我发现我需要分别对待测试,换句话说,每个方法。如果我没有弄错的话,这也是单元测试名称的来源 因此,首先,我测试这个UserManager.identifTokenIdentity;我的方法如下
public class OrderController : BaseController
{
OrderManager _orderManager;
public OrderController()
{
_orderManager = new OrderManager();
}
//Order Controllers
}
[TestMethod]
public void IdentifyToken_Returns_UserWM_On_Successful_Request()
{
UserManager userManager = new UserManager();
MD5Hasher passwordHasher = new MD5Hasher();
IEnumerable<Claim> claims = new List<Claim>
{
new Claim(ClaimTypes.Email, "creditmaster@admin.com"),
new Claim(ClaimTypes.Hash, passwordHasher.Encrypt("qW12345?"))
};
ClaimsIdentity identity = new ClaimsIdentity();
identity.AddClaims(claims);
var testResult = userManager.IdentifyToken(identity);
Assert.AreEqual(typeof(UserWM), testResult.GetType());
}
最后,如果您能够成功地分别对所有方法进行单元测试,那么当同时调用它们时,它们就会成功地工作
我还想分享下面的测试方法,其中我单元测试我的方法名是InsertUser,它在所有与用户实体相关的强制性属性按预期填充后将用户插入数据库
棘手的是,这个插件包含太多的if-else验证控件,例如
if (string.IsNullOrEmpty(user.FirstName))
{
throw new BusinessException(JsonResponse.CreateBusinessExceptionResponse(ErrorMessageConstants.UserFirstnameEmptyError), "");
}
由于这里讨论的代码行太多,我不希望您在这些代码行周围迷失方向,从而无法共享整个Insert用户
如果您在单元测试中也遇到了类似的情况,那么您应该做的唯一一件事就是将这些验证收集到另一个我称之为InsertUserValidation的方法中。现在我们有两种不同的方法:InsertUser和InsertUserValidation
现在,您可能会问,为什么我们必须将验证从主方法中分离出来。在我的例子中,我有如下依赖于时间的验证
if (activationRequest == null)
{
throw new BusinessException(JsonResponse.CreateBusinessExceptionResponse(ErrorMessageConstants.UserActivationCodeNotRequested), "");
}
else if (activationRequest.CreationTime.AddMinutes(3) < DateTime.Now)
{
throw new BusinessException(JsonResponse.CreateBusinessExceptionResponse(ErrorMessageConstants.UserActivationCodeIsTimedOut), "");
}
是的,如果我没有弄错的话,您仍然需要创建相关的实体
在我结束之前,我使用了Moq框架,不要忘记您正在分离的方法应该仍然在同一名称空间下
希望我能对这些新手有所帮助。当单独进行单元测试时,您是如何通过HttpContext的?控制员如何安排测试?提供一个可以更好地描述实际问题的上下文的方法。我认为我不能通过单元测试中的HttpContext,这是我的问题。另外,我不明白你在第二个问题中的意思。我在我的[TestClass]:private readonly OrderController\u OrderController的顶部执行此操作;public OrderTests{{u orderController=new orderController{Request=new System.Net.Http.HttpRequestMessage,Configuration=new System.Web.Http.HttpConfiguration};}这个问题缺少太多的细节,我无法有效地帮助您。提供一个示例,说明所示代码存在设计问题。在单元测试中,HttpContext将为null。我不知道用户经理或订单经理来自哪里……等等。如果没有适当的细节,就没什么可做的了。好吧,我不是专业人士,但我不明白你为什么要问ordermanager/usermanager来自哪里。我需要伪造单元测试,就好像我使用的是经过身份验证的用户一样。人们用mock来解决这类问题,但我找不到摆脱Moq的方法。我编辑我的问题是为了让它显示manager类的来源。您的答案不完整:什么是MD5Hasher,我从哪里引用它?我认为在你的第一段代码之后,剩下的都是离题的、无用的。请考虑提供针对具体问题的完整解决方案,跳过那些对主题没有价值的部分。@ LeNAROXD5M5HASHER是我将纯文本转为加密文本的类。如果我共享所有这些不相关的功能,我的答案将是无用的。在复制粘贴整个代码块之前,只需使用大脑一点!您的答案是不可验证的,因为没有提供所有代码,至少您应该提供MD5Hasher.Encrypt方法。另外,正如其他人所指出的,您提供了不必要的细节,正如我在之前的评论中所说的,您的问题与测试jwt身份验证令牌有关,而不是插入用户或验证用户功能,这与主题无关,因此,请再次提醒,我鼓励您重新制定您的答案
if (activationRequest == null)
{
throw new BusinessException(JsonResponse.CreateBusinessExceptionResponse(ErrorMessageConstants.UserActivationCodeNotRequested), "");
}
else if (activationRequest.CreationTime.AddMinutes(3) < DateTime.Now)
{
throw new BusinessException(JsonResponse.CreateBusinessExceptionResponse(ErrorMessageConstants.UserActivationCodeIsTimedOut), "");
}
[TestMethod]
public void InsertUser_Returns_UserWM_On_Successful_Request()
{
UserManager userManager = new UserManager();
MD5Hasher passwordHasher = new MD5Hasher();
Random rnd = new Random();
int dummyEmailName = rnd.Next(0, 700);
string dummyEmail = dummyEmailName.ToString() + "@gmail.com";
UserActivationRequest userActivationRequest = new UserActivationRequest
{
EMail = dummyEmail,
ActivationCode = "444855",
IsUsed = false,
IsActive = true,
ConfirmationType = 1,
ReadCount = 0
};
UserCreateAccountWM userCreateAccountWM = new UserCreateAccountWM()
{
FirstName = "Unit",
LastName = "Test",
Email = dummyEmail,
Password = passwordHasher.Encrypt("yC123456?"),
CountryID = 1,
PhoneCountryCode = 90,
MobileNumber = "5327894512",
ActivationCode = "444855"
};
var validationMock = new Mock<UserManager>();
validationMock.CallBase = true;
validationMock.Setup(x => x.InsertUserValidation(It.IsAny<UserCreateAccountWM>())).Returns(userActivationRequest); //if your validations do not return anything back, just forget about the part with .Returns()
var testResult = validationMock.Object.InsertUser(userCreateAccountWM);
Assert.AreEqual(typeof(UserWM), testResult.GetType());
}