C
C#17mo ago
skoll9233

❔ Help needed to clear database with EF between XUnit tests

I don't understand how to clear in memory database properly between tests with XUnit. I mean, I already tried a lot of stuff to do: EnsureDeleted/Created, Manual deletion, clearing the tracker. Probably I am missing something important here but I don't get what.
34 Replies
phaseshift
phaseshift17mo ago
where does InitAsync get called from? ok, so it gets called from xunit. Have you observed this whn debugging? dont you need to 'SaveChanges' at the end of the method?
skoll9233
skoll923317mo ago
Yes, I did and it did not help me either.
skoll9233
skoll923317mo ago
I tried manual deletion of entities, tried EnsureDeleted/Created, Tried to clear change tracker and so on I have a rough guess that all the tests are executed in parallel and each test shares the same database context But I am not sure about it
phaseshift
phaseshift17mo ago
xunit runs classes in parallel, not methods by default
skoll9233
skoll923317mo ago
Yes, but as I understand, for each test it creates new instance of the test class
phaseshift
phaseshift17mo ago
Yes. What kind of fixture are you using for the webAppFactory ?
skoll9233
skoll923317mo ago
Default one from Microsoft.AspNetCore.Mvc.Testing
phaseshift
phaseshift17mo ago
I was referring to the xunit type of fixture So if you want a separate db per test, why use class fixture?
skoll9233
skoll923317mo ago
I am sorry, what I do may sound stupid but I am really new to the asp net. Basically I made this project 4 days ago (migrating from java/spring btw)
phaseshift
phaseshift17mo ago
If you want something new for each test, the normal way is to 'new' it in the constructor
skoll9233
skoll923317mo ago
So, I made tests green by applying Collection attribute to the base class
skoll9233
skoll923317mo ago
So, the problem here definitely with the shared db context
phaseshift
phaseshift17mo ago
what type of in-memory db are you using?
skoll9233
skoll923317mo ago
Yes, but what I am trying to achieve is subcutaneous testing, so I want to test the core of my application as close to the real-world scenario as possible later on I will add pgsql and testcontainers Microsoft.EntityFrameworkCore.InMemory
phaseshift
phaseshift17mo ago
What you say is not consistent with the tests though you want 'real life tests', but then want to test in isolation from scratch every time? And you are blocking out parallel tests by adding Collection attribute So first, what do you want?
skoll9233
skoll923317mo ago
I have a few use cases in my application and I want to test them with the actual database rather than mocked one. As I said, later I will switch in memory db adapter to pgsql.
phaseshift
phaseshift17mo ago
So actually, you want simple small tests, and to use a fresh db each time?
skoll9233
skoll923317mo ago
Yes, but not only a database but a whole context with it: MediatR, FluentValidators, and other services that are registered inside the Program.cs
phaseshift
phaseshift17mo ago
btw, ms explicitly warns against using the EF in-mem db for actually doing DB stuff
skoll9233
skoll923317mo ago
Yeah, I saw that one. I just needed something to catch up quickly with asp.net and choose the in memory one
phaseshift
phaseshift17mo ago
ok. Well, you can specify the name of the db - you can choose a different one for each test But again, this is going the per-test route, not the class fixture route
skoll9233
skoll923317mo ago
Well, I have an idea. I may try to turn db context into transient rather than scoped. But I feel like this is a fools path as the result is unclear for me
phaseshift
phaseshift17mo ago
that definitely does not jive with "I want to test the core of my application as close to the real-world scenario as possible" and also does not fix anything
skoll9233
skoll923317mo ago
Oh, so basically I can just generate the unique database for each separated test? That makes sense!
phaseshift
phaseshift17mo ago
you need to configure the context/db builder differently, yes like here https://learn.microsoft.com/en-us/ef/core/testing/testing-without-the-database#in-memory-provider
skoll9233
skoll923317mo ago
But I did not understand you when you said "per-test" vs "per class fixture" Will I be able to use this same approach with the real database?
phaseshift
phaseshift17mo ago
no, because you cannot create multiple databases with postgres (e.g.) just by pasting a different name into the connection string
skoll9233
skoll923317mo ago
Well, I guess then I will be forced to execute tests inside separated docker environments... That's a little bit too expensive Well, thank you very much anyway! I was struggling with this issue the whole day, and now I have an understanding of what went wrong and that I have some misconceptions on my side
phaseshift
phaseshift17mo ago
It seems odd that you want multiple test sets to run against an actual db, you want them to run in parallel, but you dont want them on the same db
skoll9233
skoll923317mo ago
Well, honestly speaking I didn't think about how all of this works under the hood and how much control I have over it. Thank you again for pointing this out to me. The reason why I want to test the core with an actual database is that I want to have guarantees that a specific build works with that specific database.
phaseshift
phaseshift17mo ago
Sure. But there is generally a small amount of full system tests when compared to the number of unit/component tests. So I wouldnt expect to see a test for 'api endpoint adds one entity to the real db'
skoll9233
skoll923317mo ago
Totally agree with you, but that if you have a system at scale. What I do Is a simple CRUD where adding an entity to the db is the core usecase 🙂
phaseshift
phaseshift17mo ago
Let me put it like this, if you have more tests that are at a service level where you have the real service, interacting with the real db, then yes, you would have plenty of crud tests on the service, and also performance/stress test and parallel tests. Then aside from that, there could be numerous very thin tests that check the ASP.NET endpoints send the correct data to mocked services. You of course would have a limited number of full system tests. What I'm saying is that you do not need to be testing the entirety of the app functionality via full system tests.
Accord
Accord17mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.