并行测试中Quartz调度器重复创建引发的已存在异常问题
Quartz调度器并行测试重复创建问题解决方案
问题描述
运行并行测试时遇到错误:Quartz.SchedulerException : Scheduler with name 'DefaultQuartzScheduler' already exists
原因是每个测试都会创建独立的Web应用工厂实例,导致Quartz调度器被重复初始化。目前通过给命名空间添加[assembly: CollectionBehavior(DisableTestParallelization = true)]可以解决,但这是临时方案,而且ASP.NET依赖注入中无法直接传递Scheduler实例。
当前DI配置代码:
services.AddQuartz(options => { options.UseMicrosoftDependencyInjectionJobFactory(); }); services.AddQuartzHostedService(options => { options.WaitForJobsToComplete = true; });
可行解决方案
1. 为每个测试实例生成唯一调度器名称
修改DI配置,支持动态指定调度器名称,测试时为每个Web应用工厂分配唯一标识:
services.AddQuartz((provider, options) => { options.UseMicrosoftDependencyInjectionJobFactory(); // 从配置获取名称,测试时注入唯一值 var schedulerName = provider.GetRequiredService<IConfiguration>()["Quartz:Scheduler:Name"] ?? "DefaultQuartzScheduler"; options.SchedulerName = schedulerName; });
测试代码中覆盖配置:
var factory = new WebApplicationFactory<Program>().WithWebHostBuilder(builder => { builder.ConfigureAppConfiguration((context, config) => { config.AddInMemoryCollection(new Dictionary<string, string> { ["Quartz:Scheduler:Name"] = $"TestScheduler_{Guid.NewGuid()}" }); }); });
2. 用测试集合隔离调度器实例
把依赖Quartz的测试归到同一个集合,同一集合内的测试串行执行,不影响其他测试并行:
[CollectionDefinition("QuartzTests")] public class QuartzTestCollection : ICollectionFixture<WebApplicationFactory<Program>> { // 仅用于标记集合,无需实现方法 }
在测试类上标记集合:
[Collection("QuartzTests")] public class MyQuartzTests { // 测试逻辑 }
3. 测试时禁用Quartz Hosted Service
如果测试不需要调度器运行,可以直接移除或替换Quartz的Hosted Service:
var factory = new WebApplicationFactory<Program>().WithWebHostBuilder(builder => { builder.ConfigureServices(services => { var quartzHostedService = services.SingleOrDefault(d => d.ServiceType == typeof(IHostedService) && d.ImplementationType == typeof(QuartzHostedService)); if (quartzHostedService != null) { services.Remove(quartzHostedService); } // 可选:替换为模拟的Hosted Service services.AddSingleton<IHostedService, MockHostedService>(); }); });
内容的提问来源于stack exchange,提问作者D. Nizio
相关产品推荐
相关产品推荐

