System.AggregateException:“一个或多个托管服务未能停止。 (操作被取消。)'

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

我正在使用 XUnit 编写集成测试,我的 Web api 代码也在 C# NET 6 和 EF Core 中。

当我调试它时,它可以到达Web api及其服务层。但当它到达 EF Core 上下文查询示例

private Message? GetMessage() => _myContext.Messages.OrderBy(m => m.CreatedUtc).FirstOrDefault();
时,它会在
Program.cs
处中断。

这是

TestingWebAppFactory
类的代码

public class TestingWebAppFactory<TEntryPoint> : WebApplicationFactory<Program> where TEntryPoint : Program
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureServices(services =>
        {
            var descriptor = services.SingleOrDefault(
                d => d.ServiceType ==
                    typeof(DbContextOptions<MyContext>));

            if (descriptor != null)
                services.Remove(descriptor);

            services.AddDbContext<MyContext>(options =>
            {
                options.UseInMemoryDatabase("myinmemorydb");
            });

            var sp = services.BuildServiceProvider();
            using (var scope = sp.CreateScope())
            using (var appContext = scope.ServiceProvider.GetRequiredService<MyContext>())
            {
                try
                {
                    appContext.Database.EnsureCreated();
                }
                catch (Exception ex)
                {
                    //Log errors or do anything you think it's needed
                    throw;
                }
            }
        });
    }
}

这是我在 Xunit 中的代码

public class MyServiceTest : IClassFixture<TestingWebAppFactory<Program>>
{

    private readonly HttpClient _client;

    public MyServiceTest(TestingWebAppFactory<Program> factory)
    {
        _client = factory.CreateClient();
    }

    [Fact]
    public async Task WhenAValidMessagePosted_ThenShouldReturn()
    {
        CancellationTokenSource source = new CancellationTokenSource();
        CancellationToken token = source.Token;
        source.CancelAfter(TimeSpan.FromSeconds(5));
        var response = await _client.GetAsync("https://localhost:xxxx/api/service/message/post?cronExpresson=0");
    }
}
c# xunit
2个回答
1
投票

问题似乎可能与您在测试环境中配置 EF Core 上下文的方式有关。

尝试确保您的测试项目引用 EF Core 和 EF Core 内存数据库所需的 NuGet 包。

验证您的

MyContext
类是否继承自
DbContext
并且已正确配置。

更新

TestingWebAppFactory
类以对
TEntryPoint
使用正确的泛型类型参数 (
WebApplicationFactory
)。尝试将
Program
替换为
TEntryPoint
,如下所示:

public class TestingWebAppFactory<TEntryPoint> : WebApplicationFactory<TEntryPoint> where TEntryPoint : class
{
    // ...
}

检查您的

MyContext
类是否在测试环境中正确注册。在您的
TestingWebAppFactory
课程中,注册
Program
时,将
TEntryPoint
替换为
DbContextOptions<MyContext>
。尝试像这样更新您的
ConfigureWebHost
方法:

protected override void ConfigureWebHost(IWebHostBuilder builder)
{
    builder.ConfigureServices(services =>
    {
        var descriptor = services.SingleOrDefault(
            d => d.ServiceType == typeof(DbContextOptions<MyContext>));

        if (descriptor != null)
            services.Remove(descriptor);

        services.AddDbContext<MyContext>(options =>
        {
            options.UseInMemoryDatabase("myinmemorydb");
        });
        
        // ...
    });
}

确保

MyContext
实例在您的测试类中得到正确解析。在您的
MyServiceTest
类中,将
TestingWebAppFactory
泛型类型参数更新为
TEntryPoint
,如下所示:

public class MyServiceTest : IClassFixture<TestingWebAppFactory<Program>>
{
    private readonly HttpClient _client;

    public MyServiceTest(TestingWebAppFactory<Program> factory)
    {
        _client = factory.CreateClient();
    }

    // ...
}

希望这对您有帮助!


0
投票

我发现了类似的错误,我实现了接口

IAsyncLifetime

public class MyServiceTest : IClassFixture<TestingWebAppFactory<Program>>, IAsyncLifetime
{
    private readonly TestingWebAppFactory<Program> _factory;
    private readonly HttpClient _client;

    public MyServiceTest(TestingWebAppFactory<Program> factory)
    {
        _factory = factory;
        _client = factory.CreateClient();
    }

    public Task InitializeAsync()
    {
       using (_waf.CreateDefaultClient()) { }

       return Task.CompletedTask;
    }

    public async Task DisposeAsync()
    {
       await using var scope = _waf.Services.CreateAsyncScope();
    }

    [Fact]
    public async Task WhenAValidMessagePosted_ThenShouldReturn()
    {
        CancellationTokenSource source = new CancellationTokenSource();
        CancellationToken token = source.Token;
        source.CancelAfter(TimeSpan.FromSeconds(5));
        var response = await _client.GetAsync("https://localhost:xxxx/api/service/message/post?cronExpresson=0");
    }
}

基于这个

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