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

ASP.NET应用EF Core单元测试ChangeTracker追踪异常问题

EF Core单元测试中ChangeTracker跨测试上下文冲突问题

问题概述

我有一个ASP.NET应用,想要对其进行单元测试。尽管每次SetUp都会生成新的上下文,但ChangeTracker似乎并未自动清空(手动清空也无效)。

测试代码细节

通用测试初始化

所有测试的通用SetUp方法:

[SetUp]
public async Task SetupGeneral()
{
    context = new ContextWrapper(GenerateConnectionString());
    context.CreateDatabase();
}

ContextWrapper构造实现

public ContextWrapper(string connString)
{
    context = new Context(connString);
    ChangeTracker = context.ChangeTracker;
}

Context类是继承自DbContext的标准EF Core上下文。

具体测试类的初始化方法

问题出在继承通用测试类的测试类中,其SetUp方法如下:

[SetUp]
public async Task SetupPc()
{
    var trackedEntityCount = context.ChangeTracker.Entries().ToList();
    psu = CreatePsu();
    motherboard = CreateMotherboard();
    cpu = CreateCpu();
    @case = CreateCase();
    cpuCooler = CreateCpuCooler();
    fan = CreateFan();
    gpu = CreateGpu();
    ram = CreateRam();
    ssd1 = CreateSsd1();
    ssd2 = CreateSsd2();
    hdd = CreateHdd();

    trackedEntityCount = context.ChangeTracker.Entries().ToList();

    await context.SaveChangesAsync().ConfigureAwait(false);
}

异常现象

单独运行一个测试时一切正常,但运行多个测试时出现问题:

  • 第一个测试:函数开头的trackedEntityCount为62,创建所有实体后变为79;
  • 第二个测试:进入函数时开头的trackedEntityCount是62,创建实体后计数约为111,上下文之间似乎存在冲突。

尝试过以下方案但均无效:在通用TearDown/SetUp中清空ChangeTracker、在该测试的TearDown中清空ChangeTracker、分离所有实体、在测试TearDown中分离特定实体。第一个测试之后的所有测试都会抛出以下异常:

System.InvalidOperationException : The instance of entity type 'Case' cannot be tracked because another instance with the key value '{Id: 3}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached

注:该问题并非仅针对Case实体,调用SaveChangesAsync时任何实体都可能抛出此错误,且Id是自动生成的自增列。

实体生成示例

以下是其中一个实体生成函数示例,其他函数结构类似:

private Psu CreatePsu()
{
    var psu = new Psu()
    {
        Name = "Psu1",
        TotalPower = 650,
        Output3dot3V = 20,
        Output5V = 20,
        Output12Vp = 54,
        Output12Vm = -0.3,
        PsuEfficiency = new PsuEfficiency() { Name = "80+ Gold" },
        PsuPorts = new HashSet<PsuPort>()
            {
                new PsuPort() { PsuPortType = psuPortTypeMB, PortCount = 1 },
                new PsuPort() { PsuPortType = psuPortTypeCPU, PortCount = 1 },
                new PsuPort() { PsuPortType = psuPortTypePCIe, PortCount = 4 },
                new PsuPort() { PsuPortType = psuPortTypeSata, PortCount = 6 },
                new PsuPort() { PsuPortType = new PsuPortType { Name = "Molex" }, PortCount = 3 },
            }
    };

    context.GetDatabaseSet<Psu>().Add(psu);
    return psu;
}

补充尝试结果

在SetupPc中直接插入ChangeTracker.Clear()后,结果如下:

  • 第一个测试:开头的trackedEntityCount为0,创建实体后为29;
  • 第二个测试:开头的trackedEntityCount为0,创建实体后为64。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 18:35:26