实例化JWT令牌提供商时,具有错误的Xunit测试控制器

发布于 2025-02-09 21:08:30 字数 7572 浏览 3 评论 0原文

我使用.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

子问题:

  1. 也许我走了错误的道路,但是我应该模拟apioauthprovider,为了做到这一点,我需要注入它,为了做到这一点,我需要创建一个接口并注册为服务,但这听起来不正确。

  2. 我只需要创建一个有效的令牌。

  3. 也许它真的找不到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:

  1. 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.

  2. Do I just need to create a valid token.

  3. 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文