实例化JWT令牌提供商时,具有错误的Xunit测试控制器
我使用.NET 4.8在WebAPI(不是MVC或Core)中有一个控制器,我正在尝试使用Xunit测试。
在我进行之前,设置它的设置方式可能对单元测试是不正确的,但这是我得到的,在此阶段我不知道任何更好的信息,欢迎这方面的任何指针。
控制器中的主要问题是ApioAuthProvider的立即声明/实例化。当它创建对象时,它会立即对JWTTokenProvider进行立即声明/实例化。这是发生错误的地方,内部异常:
消息“无法加载文件或组装 'System.Configuration.configurationManager,版本= 0.0.0.0, 文化=中性,publicKeyToken = cc7b13ffcd2dddd51'。系统不能 找到指定的文件。”
但是我要向前伸出来显示代码
控制器:
using System.Net;
using System.Net.Http;
using System.Web.Http;
using TA.Services.BL.BusinessLogic;
using TA.Services.WebAPI.Providers;
using TA.Services.DTO.DTO;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
using TA.Services.BL.Interface;
namespace TA.Services.WebAPI.Controllers
{
public class AccountsController : ApiController
{
private readonly ApiOAuthProvider _jwtTokenProvider = new ApiOAuthProvider();
private readonly ICommonBL _commonBL;
private readonly ISystemSettingsBL _systemSettingsBL;
public AccountsController(ICommonBL commonBL, ISystemSettingsBL systemSettingsBL)
{
_commonBL = commonBL;
_systemSettingsBL = systemSettingsBL;
}
...
// GET: JwtToken
[HttpPost]
//[EnableCors("*", "*", "*")]
public JObject Token(User loginUserCredentials)
{
// first check the user name & password is valid one before generating token for that user.
var user = _commonBL.GetUserInformation(loginUserCredentials.UserName);
var accessToken = _jwtTokenProvider.GenerateToken(user);
return accessToken;
}
}
}
apioauthprovider:
namespace TA.Services.WebAPI.Providers
{
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.OAuth;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Web.Http.Cors;
using TA.Services.DTO.DTO;
using static TA.Services.WebAPI.Providers.JWTHelper;
[EnableCors("*", "*", "*")]
public class ApiOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly JwtTokenProvider _jwtTokenProvider = new JwtTokenProvider();
[EnableCors("*", "*", "*")]
public JObject GenerateToken(User userDetail)
{
...
return tokenResponse;
}
public static AuthenticationProperties CreateProperties(string userName, Status apiData)
{
...
return new AuthenticationProperties(data);
}
}
}
jwttokenprovider:
namespace TA.Services.WebAPI.Providers
{
using System;
using System.Configuration;
using System.Security.Claims;
using System.Text;
using System.Web.Configuration;
using System.Web;
using Microsoft.Owin.Security;
using TA.Services.BL.Interface;
using TA.Services.DTO.DTO;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
public class JwtTokenProvider : ISecureDataFormat<AuthenticationTicket>
{
private static string plainTextSecurityKey = ((MachineKeySection)ConfigurationManager.GetSection("system.web/machineKey")).ValidationKey;
private readonly Microsoft.IdentityModel.Tokens.SymmetricSecurityKey _signingKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.UTF8.GetBytes(plainTextSecurityKey));
private readonly IAuditsBL _auditsBL;
public string Protect(AuthenticationTicket data)
{
var signedAndEncodedToken = string.Empty;
...
return signedAndEncodedToken;
}
public AuthenticationTicket Unprotect(string signedAndEncodedToken)
{
ClaimsIdentity idenity = null;
...
return new AuthenticationTicket(idenity, new AuthenticationProperties());
}
}
}
我的xunit测试类:
using Moq;
using System.Net.Http;
using System.Security.Claims;
using System.Security.Principal;
using System.Web.Http;
using TA.Services.BL.Interface;
using TA.Services.DTO.DTO;
using TA.Services.WebAPI.Controllers;
using TA.Services.WebAPI.Providers;
using Xunit;
namespace TA.Services.WebAPI.Tests.Controllers
{
public class AccountsControllerTests : BaseUnitTest
{
private readonly Mock<ICommonBL> _commonBLMock;
private readonly Mock<ISystemSettingsBL> _systemSettingsBLMock;
private readonly AccountsController _accountsController;
public AccountsControllerTests()
{
_commonBLMock = new Mock<ICommonBL>();
_systemSettingsBLMock = new Mock<ISystemSettingsBL>();
_accountsController = new AccountsController(_commonBLMock.Object, _systemSettingsBLMock.Object);
}
...
}
}
例外发生在JwttokenProvider:
private readonly Microsoft.IdentityModel.Tokens.SymmetricSecurityKey _signingKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.UTF8.GetBytes(plainTextSecurityKey));
stacktrace:
at TA.Services.WebAPI.Providers.JwtTokenProvider..ctor() in C:\TA\Repos\April 20 2021\TADev\Service\TA.Services\TA.Services.WebAPI\Providers\JwtTokenProvider.cs:line 19
at TA.Services.WebAPI.Providers.ApiOAuthProvider..ctor() in C:\TA\Repos\April 20 2021\TADev\Service\TA.Services\TA.Services.WebAPI\Providers\ApiOAuthProvider.cs:line 23
at TA.Services.WebAPI.Controllers.AccountsController..ctor(ICommonBL commonBL, ISystemSettingsBL systemSettingsBL) in C:\TA\Repos\April 20 2021\TADev\Service\TA.Services\TA.Services.WebAPI\Controllers\AccountsController.cs:line 27
at TA.Services.WebAPI.Tests.Controllers.AccountsControllerTests..ctor() in C:\TA\Repos\April 20 2021\TADev\Service\TA.Services\Testing\TA.Services.WebAPI.Tests\Controllers\AccountsControllerTests.cs:line 26
子问题:
也许我走了错误的道路,但是我应该模拟apioauthprovider,为了做到这一点,我需要注入它,为了做到这一点,我需要创建一个接口并注册为服务,但这听起来不正确。
我只需要创建一个有效的令牌。
也许它真的找不到system.configuration.configurationmanager
主要问题:我应该如何解决这个问题?
注意:在正常执行下,该应用程序在此测试之外工作正常。
[UPDATE] 更改控制器使ApioAuthProvider注入了
public class AccountsController : ApiController
{
private readonly ApiOAuthProvider _jwtTokenProvider;
private readonly ICommonBL _commonBL;
private readonly ISystemSettingsBL _systemSettingsBL;
public AccountsController(ApiOAuthProvider jwtTokenProvider, ICommonBL commonBL, ISystemSettingsBL systemSettingsBL)
{
_commonBL = commonBL;
_systemSettingsBL = systemSettingsBL;
_jwtTokenProvider = jwtTokenProvider;
}
ApioAuthProvider添加到启动中的服务:
services.AddSingleton<ApiOAuthProvider>();
更改的测试脚本:
public class AccountsControllerTests : BaseUnitTest
{
private readonly Mock<ApiOAuthProvider> _apiOAuthProviderMock;
private readonly Mock<ICommonBL> _commonBLMock;
private readonly Mock<ISystemSettingsBL> _systemSettingsBLMock;
private readonly AccountsController _accountsController;
public AccountsControllerTests()
{
_apiOAuthProviderMock = new Mock<ApiOAuthProvider>();
_commonBLMock = new Mock<ICommonBL>();
_systemSettingsBLMock = new Mock<ISystemSettingsBL>();
_accountsController = new AccountsController(_apiOAuthProviderMock.Object, _commonBLMock.Object, _systemSettingsBLMock.Object);
}
...
调试测试,它一直进行,直到遇到相同的错误。没有接口,似乎不是很好模拟。
[更新结束]
I have a controller in my WebAPI (not MVC or Core) using .Net 4.8 that I'm trying to test with xUnit.
Before I proceed, the way it is setup may not be correct for unit testing, but it is what I have been given and I don't know any better at this stage, any pointers in this regard is welcome.
The main problem in the controller is the immediate declaration/instantiation of ApiOAuthProvider. As it creates the object, it in-turn does an immediate declaration/instantiation of JwtTokenProvider. This is where the error occurs, inner exception:
Message "Could not load file or assembly
'System.Configuration.ConfigurationManager, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot
find the file specified."
But I'm jumping ahead I'll show the code
Controller:
using System.Net;
using System.Net.Http;
using System.Web.Http;
using TA.Services.BL.BusinessLogic;
using TA.Services.WebAPI.Providers;
using TA.Services.DTO.DTO;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
using TA.Services.BL.Interface;
namespace TA.Services.WebAPI.Controllers
{
public class AccountsController : ApiController
{
private readonly ApiOAuthProvider _jwtTokenProvider = new ApiOAuthProvider();
private readonly ICommonBL _commonBL;
private readonly ISystemSettingsBL _systemSettingsBL;
public AccountsController(ICommonBL commonBL, ISystemSettingsBL systemSettingsBL)
{
_commonBL = commonBL;
_systemSettingsBL = systemSettingsBL;
}
...
// GET: JwtToken
[HttpPost]
//[EnableCors("*", "*", "*")]
public JObject Token(User loginUserCredentials)
{
// first check the user name & password is valid one before generating token for that user.
var user = _commonBL.GetUserInformation(loginUserCredentials.UserName);
var accessToken = _jwtTokenProvider.GenerateToken(user);
return accessToken;
}
}
}
ApiOAuthProvider:
namespace TA.Services.WebAPI.Providers
{
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.OAuth;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Web.Http.Cors;
using TA.Services.DTO.DTO;
using static TA.Services.WebAPI.Providers.JWTHelper;
[EnableCors("*", "*", "*")]
public class ApiOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly JwtTokenProvider _jwtTokenProvider = new JwtTokenProvider();
[EnableCors("*", "*", "*")]
public JObject GenerateToken(User userDetail)
{
...
return tokenResponse;
}
public static AuthenticationProperties CreateProperties(string userName, Status apiData)
{
...
return new AuthenticationProperties(data);
}
}
}
JwtTokenProvider:
namespace TA.Services.WebAPI.Providers
{
using System;
using System.Configuration;
using System.Security.Claims;
using System.Text;
using System.Web.Configuration;
using System.Web;
using Microsoft.Owin.Security;
using TA.Services.BL.Interface;
using TA.Services.DTO.DTO;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
public class JwtTokenProvider : ISecureDataFormat<AuthenticationTicket>
{
private static string plainTextSecurityKey = ((MachineKeySection)ConfigurationManager.GetSection("system.web/machineKey")).ValidationKey;
private readonly Microsoft.IdentityModel.Tokens.SymmetricSecurityKey _signingKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.UTF8.GetBytes(plainTextSecurityKey));
private readonly IAuditsBL _auditsBL;
public string Protect(AuthenticationTicket data)
{
var signedAndEncodedToken = string.Empty;
...
return signedAndEncodedToken;
}
public AuthenticationTicket Unprotect(string signedAndEncodedToken)
{
ClaimsIdentity idenity = null;
...
return new AuthenticationTicket(idenity, new AuthenticationProperties());
}
}
}
My xUnit test class:
using Moq;
using System.Net.Http;
using System.Security.Claims;
using System.Security.Principal;
using System.Web.Http;
using TA.Services.BL.Interface;
using TA.Services.DTO.DTO;
using TA.Services.WebAPI.Controllers;
using TA.Services.WebAPI.Providers;
using Xunit;
namespace TA.Services.WebAPI.Tests.Controllers
{
public class AccountsControllerTests : BaseUnitTest
{
private readonly Mock<ICommonBL> _commonBLMock;
private readonly Mock<ISystemSettingsBL> _systemSettingsBLMock;
private readonly AccountsController _accountsController;
public AccountsControllerTests()
{
_commonBLMock = new Mock<ICommonBL>();
_systemSettingsBLMock = new Mock<ISystemSettingsBL>();
_accountsController = new AccountsController(_commonBLMock.Object, _systemSettingsBLMock.Object);
}
...
}
}
The exception occurs here in JwtTokenProvider:
private readonly Microsoft.IdentityModel.Tokens.SymmetricSecurityKey _signingKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.UTF8.GetBytes(plainTextSecurityKey));
StackTrace:
at TA.Services.WebAPI.Providers.JwtTokenProvider..ctor() in C:\TA\Repos\April 20 2021\TADev\Service\TA.Services\TA.Services.WebAPI\Providers\JwtTokenProvider.cs:line 19
at TA.Services.WebAPI.Providers.ApiOAuthProvider..ctor() in C:\TA\Repos\April 20 2021\TADev\Service\TA.Services\TA.Services.WebAPI\Providers\ApiOAuthProvider.cs:line 23
at TA.Services.WebAPI.Controllers.AccountsController..ctor(ICommonBL commonBL, ISystemSettingsBL systemSettingsBL) in C:\TA\Repos\April 20 2021\TADev\Service\TA.Services\TA.Services.WebAPI\Controllers\AccountsController.cs:line 27
at TA.Services.WebAPI.Tests.Controllers.AccountsControllerTests..ctor() in C:\TA\Repos\April 20 2021\TADev\Service\TA.Services\Testing\TA.Services.WebAPI.Tests\Controllers\AccountsControllerTests.cs:line 26
Sub-questions:
Maybe I'm going down the wrong path, however should I mock ApiOAuthProvider, in order to do that I need to inject it, in order to do that, I need to create an interface and registry it as a service, but this doesn't sound right.
Do I just need to create a valid token.
Maybe it really can't find the System.Configuration.ConfigurationManager
Main Question: How should I go about resolving this?
Note: The application works just fine outside of this test, under normal execution.
[Update] Changed controller have ApiOAuthProvider injected
public class AccountsController : ApiController
{
private readonly ApiOAuthProvider _jwtTokenProvider;
private readonly ICommonBL _commonBL;
private readonly ISystemSettingsBL _systemSettingsBL;
public AccountsController(ApiOAuthProvider jwtTokenProvider, ICommonBL commonBL, ISystemSettingsBL systemSettingsBL)
{
_commonBL = commonBL;
_systemSettingsBL = systemSettingsBL;
_jwtTokenProvider = jwtTokenProvider;
}
Added ApiOAuthProvider to services in startup:
services.AddSingleton<ApiOAuthProvider>();
Changed test script:
public class AccountsControllerTests : BaseUnitTest
{
private readonly Mock<ApiOAuthProvider> _apiOAuthProviderMock;
private readonly Mock<ICommonBL> _commonBLMock;
private readonly Mock<ISystemSettingsBL> _systemSettingsBLMock;
private readonly AccountsController _accountsController;
public AccountsControllerTests()
{
_apiOAuthProviderMock = new Mock<ApiOAuthProvider>();
_commonBLMock = new Mock<ICommonBL>();
_systemSettingsBLMock = new Mock<ISystemSettingsBL>();
_accountsController = new AccountsController(_apiOAuthProviderMock.Object, _commonBLMock.Object, _systemSettingsBLMock.Object);
}
...
Debugged the test and it kept going until it got to the same error. Doesn't seem to mock very well without an interface.
[Update End]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论