简体   繁体   English

C# EF Core单元测试异常

[英]C# EF Core unit test anomaly

I have an ASP.NET application, and I want to unit test it.我有一个 ASP.NET 应用程序,我想对其进行单元测试。 The problem is, that despite the fact, that new context is generated every SetUp, the ChangeTracker doesn't seems to clear itself (and clearing manually doesn't work either).问题是,尽管每次 SetUp 都会生成新的上下文,但 ChangeTracker 似乎并没有自行清除(并且手动清除也不起作用)。

This is the general setup of every test:这是每个测试的一般设置:

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

And this is the constructor of the context wrapper:这是上下文包装器的构造函数:

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

The context class is a standard EF Core context inheriting from DbContext .上下文 class 是从DbContext继承的标准 EF Core 上下文。

The problem is this piece of code, which is one of the test class, inheriting the general test class, which contains the SetupGeneral method:问题是这段代码,它是测试class之一,继承了通用测试class,其中包含SetupGeneral方法:

[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);
}

When I run only one test, everything works perfectly.当我只运行一个测试时,一切正常。 The problem is, when I want to run multiple tests, something happens.问题是,当我想运行多个测试时,会发生一些事情。 During the first test, the trackedEntityCount at the start of the function is 62. After everything has been created, the count will be 79. When the second test arrives to this function, at the first line, the trackedEntityCount is 62, so it's correct up until that point.在第一次测试中, trackedEntityCount开头的 trackedEntityCount 为 62。创建完所有内容后,计数将为 79。当第二次测试到达此 function 时,在第一行, trackedEntityCount为 62,所以它直到那时。 But after the create functions, the count is around 111, which just doesn't make sense.但是在创建函数之后,计数大约是 111,这没有任何意义。 It seems like to me, that the contexts are conflicting with each other, or I don't know.在我看来,上下文相互冲突,或者我不知道。

I've tried almost everything.我几乎什么都试过了。 Clearing the ChangeTracker in the general TearDown/SetUp, clearing the ChangeTracker in the TearDown of this test, detaching all entities, detaching these specific entities in the test's TearDown, but nothing works.清除一般TearDown/SetUp中的ChangeTracker,清除本次测试的TearDown中的ChangeTracker,分离所有实体,分离测试的TearDown中的这些特定实体,但没有任何效果。 All tests after the first throws this exception:第一次之后的所有测试都会引发此异常:

System.InvalidOperationException: The instance of entity type 'Case' cannot be tracked because another instance with the key value '{Id: 3}' is already being tracked. System.InvalidOperationException:无法跟踪实体类型“案例”的实例,因为已在跟踪另一个具有键值“{Id:3}”的实例。 When attaching existing entities, ensure that only one entity instance with a given key value is attached附加现有实体时,请确保仅附加一个具有给定键值的实体实例

(This problem doesn't apply to the case only, any entity can throw this error, when I call the SaveChangesAsync , and the Id is an autoincrement column, so it's generated automatically) (这个问题不仅适用于这种情况,任何实体都可以抛出这个错误,当我调用SaveChangesAsync并且Id是一个自动增量列,所以它是自动生成的)

This is one of the generator functions for example, the others look the same:例如,这是生成器函数之一,其他看起来相同:

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;
}

Edit编辑

I've tried to insert ChangeTracker.Clear() directly into the SetupPc, just to see what happens.我试图将ChangeTracker.Clear()直接插入到 SetupPc 中,看看会发生什么。

First test: the first trackedEntityCount is 0, the second is 29. Second test: the first trackedEntityCount is 0, the second is 64?第一次测试:第一次trackedEntityCount为0,第二次为29。第二次测试:第一次trackedEntityCount为0,第二次为64?

I've figured it out.我已经想通了。 Thanks to @GuruStron, I started to work on this minimal reproducible example, which pointed out the error to me.感谢@GuruStron,我开始研究这个最小的可重现示例,它向我指出了错误。 Previously I initialized resources in the test file like: private readonly TestEntity = new() { Name = "Something" } I still don't know why this produces that error, but after I had changed it so that it creates everything in the SetUp method, everything started working again.以前我在测试文件中初始化了资源,例如: private readonly TestEntity = new() { Name = "Something" }我仍然不知道为什么会产生该错误,但是在我更改它以便它在 SetUp 中创建所有内容之后方法,一切又开始工作了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM