我有两个定义如下的整数测试类。当我在 ApiControllerIT 中运行测试时,所有测试都成功运行。 FoundationControllerIT 也是如此。但是,当我同时运行两者时(通过运行封闭的文件夹),测试失败。
错误信息是:
名称为“DefaultQuartzScheduler”的调度程序已存在。
我的 Startup.cs 文件中有这个定义:
services.AddSingleton (IHostedService, QuartzHostedService);
很明显,这一行导致了问题(如果我删除这一行,所有测试一起运行正常)。 所以我的问题是 - 我是 Java 的新手..所以我对 .NET Core Integ 测试框架没有很好的了解,但我的理解是 - TestServer 是为每个测试类创建的,例如一个 TestServer 用于 ApiControllerIT,另一个用于 FoundationControllerIT。这是不正确的吗?我只是很沮丧怎么会收到一条消息:
名称为“DefaultQuartzScheduler”的调度程序已存在。
当我运行两个单独的测试类时?测试服务器如何互相干扰?
public class ApiControllerIT : IClassFixture<WebApplicationFactory<Startup>>
{
private readonly WebApplicationFactory<Startup> _factory;
public ApiControllerIT(WebApplicationFactory<Startup> factory)
{
_factory = factory;
}
// tests ...
}
public class FoundationControllerIT : IClassFixture<WebApplicationFactory<Startup>>
{
private readonly WebApplicationFactory<Startup> _factory;
public FoundationControllerIT(WebApplicationFactory<Startup> factory)
{
_factory = factory;
}
// tests ...
}
2024 年 8 月更新:此问题已在 Quartz.net 的最新版本 3.12.0 中得到修复。 如果您出于任何原因使用旧版本的 Quartz.net,请参阅下文
我可能有点晚了,但我也遇到了这个问题,它将来可能对其他人仍然有用。
问题的出现是因为 WebApplicationFactory 将创建
Startup
类的两个实例。这与正常的服务启动截然不同,在正常的服务启动中,您只有一个 Startup
实例。
(您的情况可能有点不同,但我正在使用 Singleton 实例在整个应用程序中创建和管理我的调度程序。)
WebApplicationFactory 还对它们调用
ConfigureServices
和 Configure
。因此,即使你的单身人士也会出现两次,每个 Startup
实例一个。 这不是问题,因为 Startup
实例将有自己的 ServiceProvider。仅当(多个)单例实例访问某物的相同静态属性时,才会出现问题。在我们的例子中,这是在 Quartz 中使用 SchedulerBuilder
使用 SchedulerRepository的
SchedulerFactory
,这是一个 >real< singleton and uses this code:
/// <summary>
/// Gets the singleton instance.
/// </summary>
/// <value>The instance.</value>
public static SchedulerRepository Instance { get; } = new SchedulerRepository();
这意味着你的独立 Singleton 类仍然在 Quartz 中使用相同的
SchedulerRepository
,这解释了为什么你会得到异常。
根据您在测试中测试的内容,您可以选择一些选项来解决此问题。
SchedulerRepository
有一个查找方法,您可以使用它来检查调度程序是否已由另一个实例创建:public virtual Task<IScheduler?> Lookup(string schedName, CancellationToken cancellationToken = default)
- 因此您要么只采用现有的调度程序,要么生成另一个具有不同名称的调度程序我无法告诉您在您的情况下什么最有意义,因为这完全取决于您的应用程序的功能以及您想要测试的内容,但我可能会坚持使用选项 1 的一种变体。