cod*_*bot 7 c# unit-testing azure azure-managed-identity defaultazurecredential
我使用默认的 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));
}
Run Code Online (Sandbox Code Playgroud)
是否有像 httpclientfactory 这样的东西,我可以在其中注入或传递一些连接字符串,以便我告诉 DefaultAzureCredential 不要调用 Azure?
更新
我正在添加更多上下文。我使用它从 azure 获取函数应用程序中的访问令牌,以向 APIM 进行自身身份验证。所以我使用 HttpMessageHandler 来检查令牌是否不存在,调用 Azure 并获取令牌。
在功能应用程序中启动。
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddHttpClient(AppConstants.ReplyService)
//Adding token handler middleware to add authentication related details.
.AddHttpMessageHandler<AccessTokenHandler>();
}
Run Code Online (Sandbox Code Playgroud)
处理程序文件:
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");
}
Run Code Online (Sandbox Code Playgroud)
你不应该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);
}
});
}
Run Code Online (Sandbox Code Playgroud)
然后,我使用依赖注入来使用客户端:
public MyClass(BlobServiceClient blobServiceClient)
{
this.blobServiceClient = blobServiceClient;
}
Run Code Online (Sandbox Code Playgroud)
我根本不需要接触课堂DefaultAzureCredential。然后,在单元测试时,我模拟了BlobServiceClient一个抽象类。
如果您确实确定要实际使用,DefaultAzureCredential那么您的答案仍然是依赖注入。我建议你这样设置:
在你的启动中:
builder.Services.AddSingleton<TokenCredential>(() => new DefaultAzureCredential());
Run Code Online (Sandbox Code Playgroud)
然后(就像上面一样)将其注入到您的类中:
public MyClass(TokenCredential tokenCredential)
{
this.tokenCredential= tokenCredential;
}
Run Code Online (Sandbox Code Playgroud)
然后在你的测试中你嘲笑TokenCredential。你不能模拟你所创建的类new。所以你现在需要这样做