如何对 DefaultAzureCredential 方法进行单元测试

7

在使用函数应用的托管标识来获取访问令牌的同时,我正在使用默认的 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");
    }
1个回答

4

您不应该像这样使用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并获取令牌。我已经更新了问题并提供了相关信息。 - threeleggedrabbit
另外,请确保TokenCredential位于Azure.Core命名空间下,而不是Microsoft.WindowsAzure.Storage.Auth - basquiatraphaeu
同时,请确保TokenCredential位于Azure.Core命名空间下,而不是Microsoft.WindowsAzure.Storage.Auth - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接