You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用内存数据库的DbContext并行线程单元测试问题求助

问题描述

我正试图隔离并调试一个问题,首先需要编写单元测试复现该问题:PayPal会返回两种响应,有时会同时返回,进而导致重复处理——我已经排查这个bug很久了。因此我尝试编写一个同时处理两个请求的测试,但遇到了如下错误:

在之前的操作完成前,此上下文实例启动了第二个操作。这通常是由于不同线程同时使用同一个DbContext实例导致的。有关如何避免DbContext线程问题的更多信息...

测试数据库的创建代码如下:

var builder = new DbContextOptionsBuilder<PaymentsContext>()
    .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString());
if (_output != null)
{
    builder = builder.LogTo(_output.WriteLine);
}
var db = new PaymentsContext(builder.Options);
db.Database.EnsureCreated();

内存数据库依赖DbContext本身,而DbContext无法同时被多线程调用。生产环境中每个请求都有指向同一数据库的独立DbContext,因此没有问题。请问是否有办法编写我需要的测试?

解决方案

要模拟生产环境的并发场景,核心是让每个线程使用独立的DbContext实例,但共享同一个InMemory数据库,这样既遵守DbContext的线程安全规则,又能模拟多个请求操作同一数据源的情况。

具体实现步骤:

  • 固定共享的内存库名称:测试开始时生成唯一数据库名称,所有DbContext实例都使用这个名称,确保连接到同一内存数据库。
  • 单例初始化数据库:仅用一个DbContext实例执行EnsureCreated()完成初始化,避免重复创建。
  • 每个线程独立创建DbContext:在并发任务中,各自实例化PaymentsContext,用using包裹保证资源及时释放。

修改后的测试代码示例:

// 生成唯一数据库名称,所有并发任务共享
var testDbName = Guid.NewGuid().ToString();
var optionsBuilder = new DbContextOptionsBuilder<PaymentsContext>()
    .UseInMemoryDatabase(databaseName: testDbName);

if (_output != null)
{
    optionsBuilder.LogTo(_output.WriteLine);
}

// 初始化数据库(仅执行一次)
using (var initDb = new PaymentsContext(optionsBuilder.Options))
{
    initDb.Database.EnsureCreated();
    // 可在此添加测试初始数据
}

// 模拟两个并发的PayPal响应处理任务
var task1 = Task.Run(() =>
{
    using (var db = new PaymentsContext(optionsBuilder.Options))
    {
        // 第一个响应的处理逻辑
    }
});

var task2 = Task.Run(() =>
{
    using (var db = new PaymentsContext(optionsBuilder.Options))
    {
        // 第二个响应的处理逻辑
    }
});

await Task.WhenAll(task1, task2);

// 验证结果:检查是否出现重复处理
using (var verifyDb = new PaymentsContext(optionsBuilder.Options))
{
    // 断言逻辑,例如检查数据是否被重复插入
}

额外注意事项:

  • InMemory数据库对并发的支持有限,但足以覆盖单元测试的场景需求。
  • 若测试涉及事务,需注意InMemory数据库对事务的支持存在局限性,需根据实际逻辑调整。

内容的提问来源于stack exchange,提问作者Etienne Charland

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 04:42:45