【问题标题】:How to Unit test DefaultAzureCredential Method如何对 DefaultAzureCredential 方法进行单元测试
【发布时间】:2021-07-29 17:02:30
【问题描述】:

我正在使用默认的 Azure 凭据方法获取访问令牌,同时使用函数应用的托管标识获取访问令牌。我能够获取令牌。但现在我不确定我将如何对该方法进行单元测试。这是当前状态

private async Task RefreshTokenCache()
{
    var tokenCredential = new DefaultAzureCredential();
    var accessToken = await tokenCredential.GetTokenAsync(
        new TokenRequestContext(scopes: new string[] { _config[AppConstants.ADAPIAppId] + "/.default" }) { });
    accessTokenCache.Set(AppConstants.AccessToken, accessToken.Token, DateTimeOffset.Now.AddMinutes(55));
}

有没有类似 httpclientfactory 的东西,我可以在其中注入或传递一些连接字符串,以便告诉 DefaultAzureCredential 不要调用 Azure?

更新

我正在添加更多上下文。我正在使用它从 azure 获取我的函数应用程序中的访问令牌,以向 APIM 进行身份验证。所以我正在使用 HttpMessageHandler,因为我正在检查如果令牌不存在,请调用 Azure 并获取令牌。

在 Function App 中启动。

public override void Configure(IFunctionsHostBuilder builder)
{
 builder.Services.AddHttpClient(AppConstants.ReplyService)
 //Adding token handler middleware to add authentication related details.
 .AddHttpMessageHandler<AccessTokenHandler>();
}

处理程序文件:

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 {
 // Use the token to make the call.
 // other details
 request.Headers.Authorization = new AuthenticationHeaderValue(AppConstants.AuthHeader, await GetToken());
  return await base.SendAsync(request, cancellationToken);
 }
 
private async Task<string> GetToken(bool needsRefresh = false)
{
 if (accessTokenCache.GetCount() == 0 || needsRefresh)
 {
  var tokenCredential = new DefaultAzureCredential();
  var accessToken = await tokenCredential.GetTokenAsync(
  new TokenRequestContext(scopes: new string[] { _config["AppId"] + "/.default" }) { });
   accessTokenCache.Set("accessToken", accessToken.Token, DateTimeOffset.Now.AddMinutes(55));
     }
     return accessTokenCache.Get("accessToken")?.ToString() ?? throw new Exception("Unable to Fetch Access Token from Cache");
    }

【问题讨论】:

    标签: c# azure unit-testing azure-managed-identity defaultazurecredential


    【解决方案1】:

    你不应该像这样使用DefaultAzureCredential。它需要作为DI层的一部分注入到服务中,例如这里我设置了一个新的BlobServiceClient

    private static void addAzureClients(IFunctionsHostBuilder builder)
    {
        builder.Services.AddAzureClients(builder =>
        {
            try
            {
                builder.AddBlobServiceClient(Environment.GetEnvironmentVariable("AzureWebJobsStorage"));
    
                builder.UseCredential(new DefaultAzureCredential());
            }
            catch(Exception ex)
            {
                throw new Exception($"Error loading AddBlobServiceClient: {Environment.GetEnvironmentVariable("AzureWebJobsStorage")}", ex);
            }
        });
    }
    

    然后我使用依赖注入来消费客户端:

    public MyClass(BlobServiceClient blobServiceClient)
    {
        this.blobServiceClient = blobServiceClient;
    
    }
    

    而且我根本不需要接触DefaultAzureCredential 类。然后在单元测试时我模拟BlobServiceClient 这是一个抽象类。


    如果您确实确定要实际使用DefaultAzureCredential,那么您的答案仍然是依赖注入。我建议你这样设置:

    在您的创业公司中:

    builder.Services.AddSingleton<TokenCredential>(() => new DefaultAzureCredential());
    

    然后(很像上面)将它注入你的类:

    public MyClass(TokenCredential tokenCredential)
    {
        this.tokenCredential= tokenCredential;
    
    }
    

    然后在您的测试中模拟TokenCredential。您不能模拟您new 的课程。所以你现在需要这样做

    【讨论】:

    • 我正在添加更多上下文。我正在使用它从 azure 获取我的函数应用程序中的访问令牌,以向 APIM 进行身份验证。所以我正在使用 HttpMessageHandler ,因为我正在检查如果令牌不存在,请调用 Azure 并获取令牌。我已经用信息更新了问题。
    猜你喜欢
    • 1970-01-01
    • 2011-10-18
    • 2017-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多