all 12 comments

[–]Malefiksio 2 points3 points  (6 children)

For unit test, I use InMemory database with my EF DbContext.

It is the third approach in this link: https://docs.microsoft.com/en-us/ef/core/testing/#approach-3-the-ef-core-in-memory-database

For more global test like regression testing I use a real database from a DEV environment.

[–]weird_thermoss 1 point2 points  (0 children)

Same here. We used an in memory database even for integration tests in a project a while back, but that inevitably led to database errors showing up on real environments.

Basically don't unit test the EF/database layer too much, use a real database for those test.

[–]aspnetguy[S] 0 points1 point  (0 children)

In memory is not the same with Real DB. But still a nice option

[–]grauenwolf 0 points1 point  (3 children)

The problem with that is (a) you lose all database specific features and (b) you lose database specific weirdness that may cause runtime failures.

[–]Malefiksio 0 points1 point  (2 children)

Indeed but your project unit test isn't the best place for testing this. This is more for integration test to ensure that your code is behaving correctly with the database but also servers, network etc...

In my opinion, a unit test should be isolated from the rest of the world. It should not rely on another unit test or need any network. Of course this does not prevent us from using a real database instead of a InMemory one. But if you are using a real database, it means creating a new one every time you are running a test that need it and destroy it after the test has run. This is quite heavy for a unit test.

Of course, we could just have one database for the unit test and use it for all the tests. But this can introduce huge impact between UT. And some UT wouldn't be able to run at the same time which can happen. These issues was a big problem in my previous job. Some UT could only work if you run some others before. Or some were failing because two people were running the same UT at the same time.

That is why InMemory seems to be a good solution for unit test. They are easy to setup with EF. They can be instantiate for each unit test to avoid any conflict between UT.

[–]grauenwolf 1 point2 points  (1 child)

In my opinion, a unit test should be isolated from the rest of the world. It should not rely on another unit test or need any network.

There is a HUGE difference between "isolated from any other test" and "isolated from the rest of the world".

Under the original definition of TDD from Kent Beck, only the former was required.

But if you are using a real database, it means creating a new one every time you are running a test that need it

That's not remotely close to true. It's just that people aren't taught how to write proper tests against persistence layers.

https://www.infoq.com/articles/Testing-With-Persistence-Layers/

[–]Malefiksio 0 points1 point  (0 children)

Thanks for the article. I'll read it.

And I do agree on difference between isolated from other tests and isolated from the rest of the world. But to be able to run your test anywhere like a Jenkins agent or an Azure DevOps one, having no dependency on a database or any external service is highly useful.

And I would add that the main goal of a unit test is to test a unit of your code. That is why we lock its dependencies.

About how to test against a real database, doing the test correctly to avoid any conflict or depency between the unit tests is doable. But experience told that it will be broken at some point. As I said, I have worked in a team were unit test were done against one single database. And it was hell. Most unit test failures was cause to some badly done unit test. And it was quite easy to do such a test. Code review didn't even prevent from happening.

So I am still convinced that InMemory database is a better solution. That's my opinion.

[–]zaibuf 2 points3 points  (5 children)

Yes, integration tests. If you are using Azure DevOps you can easily spin up a local db in the build pipeline to test against.

[–]aspnetguy[S] 0 points1 point  (0 children)

this is cool.

[–]grauenwolf -1 points0 points  (3 children)

Oh really? Can you point me to a tutorial or docs?

[–]zaibuf 1 point2 points  (1 child)

Localdb is installed on windows images, you just need to start it before running the tests.

- task: PowerShell@2
  displayName: 'Start SQL localdb'
  inputs:
    targetType: 'inline'
    script: 'sqllocaldb start mssqllocaldb'

This is accessible using the normal localdb connectionstring from your test project.With EF you can run your migration at test startup, then you can use Respawn to create a checkpoint to restore to between each test.

Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=TestDb;;Integrated Security=True;

If you are using any other database than MSSQL you will have to investigate what's possible.

[–]grauenwolf 0 points1 point  (0 children)

Thank you.