使用WebApplication.CreateBuilder集成测试时,如何规避Dapr外部配置调用?
解决WebApplicationFactory测试中Dapr密钥存储外部调用的问题
针对你在集成测试中遇到的Dapr外部调用无法跳过的问题,这里提供几种可行的解决方案:
方案一:通过环境变量控制Dapr密钥存储的加载
在Program.cs中添加环境判断,仅在非测试环境下加载Dapr密钥存储,测试时通过WebApplicationFactory指定测试环境并注入模拟配置:
修改Program.cs
var builder = WebApplication.CreateBuilder(args); // 添加基础服务 builder.Services.AddApplication(); builder.Services.AddInfrastructure(builder); builder.Services.AddPresentation(builder); // 仅在非Test环境下添加Dapr密钥存储 if (!builder.Environment.IsEnvironment("Test")) { builder.Configuration.AddDaprSecretStore("secrets", new DaprClientBuilder().Build()); } var app = builder.Build();
自定义WebApplicationFactory
public class TestWebApplicationFactory<TProgram> : WebApplicationFactory<TProgram> where TProgram : class { protected override void ConfigureWebHost(IWebHostBuilder builder) { // 设置测试环境 builder.UseEnvironment("Test"); // 注入模拟的密钥配置,替代Dapr获取的真实值 builder.ConfigureAppConfiguration((context, config) => { config.AddInMemoryCollection(new Dictionary<string, string> { {"YourSecretKey1", "TestSecretValue1"}, {"YourSecretKey2", "TestSecretValue2"} // 按需添加所有需要模拟的密钥 }); }); } }
方案二:通过依赖注入替换DaprClient
避免在Program.cs中直接实例化DaprClient,改为从DI容器获取,这样测试时可以替换为Mock实现:
修改Program.cs
var builder = WebApplication.CreateBuilder(args); // 先注册DaprClient到DI容器 builder.Services.AddDaprClient(); // 添加基础服务 builder.Services.AddApplication(); builder.Services.AddInfrastructure(builder); builder.Services.AddPresentation(builder); // 从DI容器获取DaprClient来添加密钥存储 using var serviceProvider = builder.Services.BuildServiceProvider(); var daprClient = serviceProvider.GetRequiredService<DaprClient>(); builder.Configuration.AddDaprSecretStore("secrets", daprClient); var app = builder.Build();
测试中替换为Mock DaprClient
public class TestWebApplicationFactory<TProgram> : WebApplicationFactory<TProgram> where TProgram : class { protected override void ConfigureWebHost(IWebHostBuilder builder) { builder.ConfigureServices(services => { // 移除原有DaprClient注册 var daprClientDescriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DaprClient)); if (daprClientDescriptor != null) { services.Remove(daprClientDescriptor); } // 创建Mock的DaprClient,模拟密钥获取逻辑 var mockDaprClient = new Mock<DaprClient>(); mockDaprClient .Setup(client => client.GetSecretAsync("secrets", It.IsAny<string>(), It.IsAny<CancellationToken>())) .ReturnsAsync((string store, string key, CancellationToken ct) => new Dictionary<string, string> { { key, $"Test_{key}" } }); // 将Mock实例注册到DI容器 services.AddSingleton(mockDaprClient.Object); }); } }
方案三:拆分Program.cs的配置逻辑(可选)
如果需要更灵活的控制,可以将添加Dapr密钥存储的逻辑抽离为可扩展的方法,比如使用部分类:
在主项目中定义Program的部分类
// Program.cs var builder = WebApplication.CreateBuilder(args); builder.Services.AddApplication(); builder.Services.AddInfrastructure(builder); builder.Services.AddPresentation(builder); // 调用可重写的方法添加密钥存储 AddDaprSecretStore(builder); var app = builder.Build(); // 定义虚方法用于扩展 partial void AddDaprSecretStore(WebApplicationBuilder builder);
// Program.Dapr.cs(主项目中) partial class Program { partial void AddDaprSecretStore(WebApplicationBuilder builder) { builder.Configuration.AddDaprSecretStore("secrets", new DaprClientBuilder().Build()); } }
在测试项目中重写该方法
// 测试项目中的Program.Test.cs partial class Program { partial void AddDaprSecretStore(WebApplicationBuilder builder) { // 测试环境下不添加Dapr密钥存储,直接注入模拟配置 builder.Configuration.AddInMemoryCollection(new Dictionary<string, string> { {"YourSecretKey", "TestValue"} }); } }
内容的提问来源于stack exchange,提问作者morteng
相关产品推荐
相关产品推荐

