Как выполнить модульное тестирование методом DefaultAzureCredential

#c# #azure #unit-testing #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));
}
 

Есть ли что-нибудь вроде 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>();
}
 

Файл обработчика:

 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:

Тебе 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 . Так что вам нужно сейчас это сделать

Комментарии:

1. Я добавляю больше контекста. Я использую это для извлечения маркера доступа в моем функциональном приложении из azure для аутентификации в APIM. поэтому я использую HttpMessageHandler, чтобы проверить, не существует ли токена, позвоните в Azure и получите токен. Я обновил вопрос с информацией.