I have an ASP.NET application, and I want to unit test it. 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).
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.
The problem is this piece of code, which is one of the test class, inheriting the general test class, which contains the SetupGeneral method:
[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. But after the create functions, the count is around 111, which just doesn't make sense. 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. 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. 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)
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.
First test: the first trackedEntityCount is 0, the second is 29.
Second test: the first trackedEntityCount is 0, the second is 64 ?