我正在使用 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");
}
}
问题似乎可能与您在测试环境中配置 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();
}
// ...
}
希望这对您有帮助!
我发现了类似的错误,我实现了接口
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");
}
}
基于这个。