You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Xunit中Mock Azure DefaultAzureCredential适配DevOps流水线

解决方法

1. 重构原代码,通过依赖注入实现可测试性

原代码直接在方法内实例化DefaultAzureCredential,导致无法Mock。我们需要依赖注入TokenCredential接口(DefaultAzureCredential实现了该接口),让代码解耦:

重构后的业务代码

// 类的构造函数注入依赖
private readonly IConfiguration _configuration;
private readonly ILogger _logger;
private readonly TokenCredential _tokenCredential;

public YourServiceClassName(IConfiguration configuration, ILogger logger, TokenCredential tokenCredential)
{
    _configuration = configuration;
    _logger = logger;
    _tokenCredential = tokenCredential;
}

private async Task<AccessToken> AcquireManagementAccessTokenAsync(CancellationToken cancellationToken)
{
    var scope = _configuration.GetValue<string>("Azure:ArmAuthScope");

    bool userManagedIdentity;
    bool.TryParse(_configuration.GetValue<string>("Azure:UseManagedIdentity"), out userManagedIdentity);

    AccessToken token = new AccessToken();            
    
    if (userManagedIdentity)
    {
        try
        {
            // 使用注入的TokenCredential,而非直接实例化
            token = await _tokenCredential.GetTokenAsync(new TokenRequestContext(new[] { scope }), cancellationToken);
        }
        catch (Exception ex)
        {
            _logger?.LogError(ex.Message);
        }
    }           
   
    return token;
}

2. 编写单元测试时Mock TokenCredential

使用Moq框架模拟TokenCredential的GetTokenAsync方法,返回预设的AccessToken,完全脱离Azure权限环境运行测试:

单元测试示例

using Moq;
using Azure.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

[TestClass]
public class YourServiceClassNameTests
{
    [TestMethod]
    public async Task AcquireManagementAccessTokenAsync_ManagedIdentityEnabled_ReturnsMockedToken()
    {
        // 1. 模拟配置项
        var mockConfig = new Mock<IConfiguration>();
        mockConfig.Setup(c => c.GetValue<string>("Azure:ArmAuthScope")).Returns("https://management.azure.com/.default");
        mockConfig.Setup(c => c.GetValue<string>("Azure:UseManagedIdentity")).Returns("true");

        // 2. 模拟Logger
        var mockLogger = new Mock<ILogger<YourServiceClassName>>();

        // 3. 模拟TokenCredential,返回预设令牌
        var mockTokenCredential = new Mock<TokenCredential>();
        var mockedToken = new AccessToken("fake-valid-token", DateTimeOffset.UtcNow.AddHours(1));
        mockTokenCredential.Setup(tc => tc.GetTokenAsync(
            It.IsAny<TokenRequestContext>(), 
            It.IsAny<CancellationToken>()))
            .ReturnsAsync(mockedToken);

        // 4. 实例化被测服务
        var sut = new YourServiceClassName(mockConfig.Object, mockLogger.Object, mockTokenCredential.Object);

        // 5. 执行测试方法
        var result = await sut.AcquireManagementAccessTokenAsync(CancellationToken.None);

        // 6. 验证结果
        Assert.AreEqual("fake-valid-token", result.Token);
        Assert.IsTrue(result.ExpiresOn > DateTimeOffset.UtcNow);
    }

    [TestMethod]
    public async Task AcquireManagementAccessTokenAsync_ManagedIdentityDisabled_ReturnsEmptyToken()
    {
        // 模拟配置项
        var mockConfig = new Mock<IConfiguration>();
        mockConfig.Setup(c => c.GetValue<string>("Azure:UseManagedIdentity")).Returns("false");

        var mockLogger = new Mock<ILogger<YourServiceClassName>>();
        var mockTokenCredential = new Mock<TokenCredential>();

        var sut = new YourServiceClassName(mockConfig.Object, mockLogger.Object, mockTokenCredential.Object);

        var result = await sut.AcquireManagementAccessTokenAsync(CancellationToken.None);

        Assert.IsEmpty(result.Token);
    }
}

3. 生产环境注入真实凭据

在Program.cs(.NET 6+)中注册DefaultAzureCredential作为TokenCredential的实现,保证生产环境正常使用真实权限:

Program.cs配置示例

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

修改后,单元测试可完全脱离Azure环境执行,DevOps流水线中的测试不再因权限问题失败。

内容的提问来源于stack exchange,提问作者VMG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 06:06:32