ASP.NET Core 集成测试中的 WebApplicationFactory 和 TestServer

问题描述 投票:0回答:1

我有两个定义如下的整数测试类。当我在 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 ...

}
asp.net-core integration-testing quartz-scheduler
1个回答
4
投票

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
,这解释了为什么你会得到异常。


根据您在测试中测试的内容,您可以选择一些选项来解决此问题。

  1. SchedulerRepository
    有一个查找方法,您可以使用它来检查调度程序是否已由另一个实例创建:
    public virtual Task<IScheduler?> Lookup(string schedName, CancellationToken cancellationToken = default)
    - 因此您要么只采用现有的调度程序,要么生成另一个具有不同名称的调度程序
  2. 捕获异常并且不执行任何操作。 (只有当你的测试不需要 Quartz 时,这才有意义,这可能不太可能,但我仍然想列出这个选项)

我无法告诉您在您的情况下什么最有意义,因为这完全取决于您的应用程序的功能以及您想要测试的内容,但我可能会坚持使用选项 1 的一种变体。

© www.soinside.com 2019 - 2024. All rights reserved.