Testing Entity Framework Core Correctly in .NET
Summary
TLDRIn this video, Nick discusses the common mistake of using an in-memory database for integration tests with EF Core, which can lead to unreliable tests and missed critical application flow issues. He demonstrates a simple API example and shows how replacing the real database provider with an in-memory version during testing can be problematic. Nick then presents a solution using test containers to ensure tests are run against a real database, maintaining the integrity of the integration testing process. The video also promotes a new course on messaging in .NET with MassTransit, highlighting its importance for developers.
Takeaways
- 🚫 Avoid using the in-memory provider for integration tests with EF Core as it does not accurately test the database integration.
- 🔍 Integration tests should test the critical component of the application's flow, including the conversion of the DbContext code to the database queries.
- 💡 The in-memory provider can lead to flaky tests that do not reflect the real-world failures of the application.
- 🛠️ Demonstrated a simple customers API with integration tests, showing how to properly set up and run tests.
- 🔗 Highlighted the importance of injecting the app DbContext into services to ensure that the database context is tested correctly.
- 📝 Discussed two schools of thought on validating tests: validating API responses and validating database objects directly.
- 🔄 Showed how to override the configure web host in tests to replace the real database provider with the in-memory provider.
- 📚 Provided a step-by-step guide on how to add the in-memory package and configure services to use it for testing.
- 🚀 Introduced Testcontainers as a solution to use the real database in integration tests by running a containerized version of the database.
- 🛑 Explained how to configure Testcontainers to start and stop a database container asynchronously for each test run.
- 🔄 Showed how to pass the connection string from the Testcontainers database to the application for real database testing in CI/CD pipelines.
Q & A
What is the single biggest mistake people make when writing integration tests for an application using EF Core?
-The biggest mistake is replacing the real database provider with the in-memory version during testing. This can lead to flaky tests that do not accurately represent the application's behavior with the actual database.
Why are integration tests that use the in-memory provider not considered good tests?
-They are not good because they remove the critical component of the application's data flow, which includes the conversion of the DbContext code and query generations, leading to tests that do not fail in the same way the application would in real scenarios.
What is the purpose of the video presented by Nick?
-The purpose of the video is to explain the common mistake made in EF Core integration testing and to show how to solve the problem by using real databases with the help of test containers.
What is the role of the DbContext in the integration tests discussed in the video?
-The DbContext is a critical component that needs to be tested as it is responsible for the conversion of the application's data flow to what the database accepts. Testing it with an in-memory provider does not accurately reflect its behavior with a real database.
How does Nick demonstrate the mistake in the integration tests?
-Nick demonstrates the mistake by showing how developers replace the real database provider with an in-memory provider in their integration tests, which leads to unreliable tests.
What is the alternative solution to using an in-memory provider for integration tests presented in the video?
-The alternative solution is to use test containers to run integration tests against a real database, ensuring that the tests are more reliable and accurately represent the application's behavior.
What is the significance of using the same database as the production environment in integration tests?
-Using the same database ensures that the tests are testing the actual integration points of the application, including query generations and database interactions, which are crucial for identifying potential issues before deployment.
How does Nick use test containers to run integration tests with a real database?
-Nick uses test containers by installing a Postgres container and configuring it to work with the application's DbContext. This allows the integration tests to run against a real database environment.
What is the benefit of using Docker containers in the CI pipeline for integration tests?
-Docker containers in the CI pipeline ensure that the integration tests run in a consistent and isolated environment, similar to production, which helps in identifying issues early in the development cycle.
What is the course being promoted in the video, and what does it cover?
-The course being promoted is 'From 0 to Hero Messaging in .NET with MassTransit'. It covers advanced concepts and production-ready patterns for messaging in .NET, including the Outbox pattern and the Saga pattern, using MassTransit, a popular library for messaging in .NET applications.
How does Nick ensure that the integration tests are not just functional tests but also test the integration points?
-Nick ensures this by using test containers to run the tests against a real database, which includes the actual database interactions and query generations, making the tests more meaningful and representative of the application's behavior.
Outlines
🚫 Avoiding Flaky Integration Tests with EF Core
In this video, Nick discusses a common mistake made when writing integration tests for applications using Entity Framework Core (EF Core). He emphasizes the importance of not replacing the real database provider with an in-memory version during testing, as this can lead to unreliable tests that do not accurately reflect the application's behavior with the actual database. Nick demonstrates this with a simple customers API example, showing how tests might pass with an in-memory provider but fail with the real database. He also explains the significance of testing the DB context code and query generation as part of the integration process. The video includes a walkthrough of a flawed test setup and a correct approach using real database testing.
📚 Leveraging Test Containers for Reliable Integration Testing
The second paragraph of the video script introduces a course on messaging in .NET with MassTransit, a popular library for messaging. The course promises to cover both basic and advanced concepts, including production-ready patterns like the Outbox pattern and the Saga pattern. Nick then transitions back to the main topic, explaining how to properly conduct integration tests using test containers with a real database. He details the process of setting up a test container for PostgreSQL, configuring it with the web application factory, and ensuring that the tests run against a real database instance. This approach ensures that the tests are reliable and accurately reflect the application's behavior with the actual database, which is crucial for maintaining code quality and reliability in continuous integration pipelines.
Mindmap
Keywords
💡Integration Test
💡EF Core
💡In-Memory Database
💡Flaky Tests
💡Database Context
💡Query Generation
💡Web Application Factory
💡DI Container
💡Test Containers
💡Docker
💡CI Pipeline
Highlights
The single biggest mistake made in integration testing with EF Core is replacing the real database provider with the in-memory version.
Using the in-memory provider for integration tests can lead to flaky tests and a failure to test the critical component of the application's flow.
Query generations are part of the integration point, and changing to in-memory removes the conversion, leading to unreliable tests.
The video will explain the problem and demonstrate a solution to avoid using the in-memory provider for integration tests.
A simple customers API is used as an example to illustrate the integration testing process.
The importance of injecting an app DB context into the customer service is emphasized for proper integration testing.
A common mistake is to replace the real database connection string with an in-memory provider in the program.cs file for integration tests.
The video shows two schools of thought on validating tests: one through API response and the other by directly querying the database.
The video demonstrates how to override the configure web host to replace the real provider with the in-memory one for testing.
Instructions on adding the Microsoft.EntityFrameworkCore.InMemory package for using the in-memory database are provided.
The process of removing the real database configuration and adding the in-memory database configuration is shown.
Debugging the integration tests with breakpoints at the controller and service levels is demonstrated.
The video points out that using in-memory for integration tests is more of a functional test rather than a true integration test.
A new course on messaging in .NET with MassTransit is announced, highlighting its importance and offering a discount.
The solution to use real databases for integration tests involves using test containers with the appropriate database technology.
Instructions on configuring test containers with PostgreSQL and integrating them into the Web Application Factory are given.
The video shows how to start and stop a container asynchronously for testing and how to pass the connection string from the container.
The importance of adding test container configuration to CI pipelines for reliable integration tests is discussed.
The video concludes by inviting viewers to share their testing experiences and thanking them for watching.
Transcripts
hello everybody I'm Nick in this video
I'm going to talk about the single
biggest mistake that people make when
they write integration test for an
application that is using EF core and
that is replacing the real database
provider during testing with the
inmemory version if you have integration
test right now on EF core and you
replace whatever you're using post
equals server Cosmos DB and you replace
that with inmemory provider you don't
have integration tests or at least you
don't have good integration tests those
things are flaky those things are bad
and they're not testing a critical
component of your application's flow
which is the conversion of your DB
context code and all that link and
everything you've written there to
whatever your database accepts those
query Generations are part of your
integration point and changing that to
the inmemory is a massive no no because
you completely remove that conversion
which leads to very very flaky tests and
your integration tests won't fail in the
same way your application will fail when
the time comes for it to fail so in this
video I'm going to explain all that and
I will show you how you can solve that
problem very very easily so let me show
what I have here I have a simple
customers API over here and I also have
an integration test project which does
have integration tests so what I'm going
to do is just first run the API to show
you what I have here so the API is
running I'll go to insomnia and I'll go
and create a customer so let's say I
want to create at Nick chaps over here
so customer has been created and I can
actually see that the customer has been
created because I can see the customer
over here they can retrieve the customer
updated deleted and so on and let's say
we wanted to write integration tests for
something like this I'll just delete
this customer first and show you what I
have in my services because the most
important part is that I'm injecting an
app DB context into the customer service
and then I have all of my n framework
core code here so the mistake that
people make is that they say oh in your
program.cs you register your real
postest connection string and all that
what you're going to do in your
integration test is you're going to
replace that with your inmemory provider
so what I'll do is I'm going to go to my
test here I have two tests testing the
exact same thing the reason for that is
because the sort of two schools of
thought when it comes to validating your
test one says that you can simply
validate the response that you get from
the API because those are integration
tests using the web application Factory
but there's another one that says you
should go all the way down to your
database get that object you created and
validated that way what I did is I added
both you can choose to do whatever you
want I don't want to have the discussion
to be focused on that that's why I'm
covering both approaches the main thing
is that people would go into the web
application Factory and they would do
the following they would say override
the configure web host which gives you
access to the web host Builder and now
you can say Builder do configure
services or configure test services and
what this does is it gives you access to
the DI container which means I can
actually say remove the real provider
now because it's time for me to run my
tests and use the inmemory one how can I
do that well first you need to add the
microsoft. framework core. inmemory
package over here by the way all this
code is in the description down below
and then once you do that to wire entty
framework to use the inmemory version
you have to first remove the
configuration of postgress so what you
would say is get the single registration
so service do service type equals type
of the DB context options of that DB
context so DB context that's enough you
don't need to remove the DB context all
you need to remove is the options the
configuration and then you can say add
DB context over here app DB context and
you can say that configure this to use
the inmemory database I'm going to give
it a name I'm just going to say tests
and that's it and now if I go ahead and
I kill my database so database is not
running as you can see connection
refused if I go ahead and I run my
integration test which I have to so if I
run it they're both going to pass and
this actually does work I'm going to
just go ahead and stick a break point
over here and let's stick a break point
on the controller level as well over
here so if I go back to my test and I
say go ahead and debug it then you'll
see and I'm going to need another break
point here too then you'll see it's
coming here it's going to the API making
that call using the we application
Factory the request comes in creates the
user retener response all that using the
inmemory DB context then comes back gets
the response customer was created on the
response level but we also want to check
the database so I have access to the DB
context which as you can see over here
is the inmemory one so I'm going to say
just select everything again database is
not running but I'm getting a response
and I'm validating the problem is that
this is more of a functional test this
doesn't actually test my integration
point now before I move on I'd like to
let you know that we just launched a
brand new course on home train call
from0 to Hero messaging in.net with mass
transit and is is an amazing 6 and 1
half hour course by Arena SCU will teach
you everything you need to know about
Q's pubsub messages but also show you
how you can use it with M Transit which
is the most popular library for doing
messaging in net by far messaging exists
in basically every single application
and if you join a company it is very
very likely they will be using mass
transit so you must know both Concepts
very very well Anda want only teach you
the basics but you will also go into
very very Advanced production ready
patterns such as the out books pattern
The Saga pattern and so on the concept
in the library is a must know for every
single developer and to celebrate the
launch the first 400 of you can use
discount code Transit 20 at checkout to
get 20% off now back to the video so how
would you make this test be what it
should be which is using the real
database well with test containers so
what you would do is you would say test
containers and then choose a database
technology that you use in this case is
postgress I'm going to say install that
and then I'm just going to configure
slightly my iclass picture for the web
application Factory so I'm going to say
that this has an i async lifetime
because I want to start and stop a
container asynchronously so yes we are
going to use Docker but don't worry your
CI almost definitely supports Docker I'm
going to say that this is actually a new
method here we go and then I'm going to
add my container so I'm going to say
private read only postgress SQL
container and that's going to be my
database container and that's going to
be a new post SQL Builder so I'm going
to say with username workshop with
password password which is what I have
in the real application to and then with
database my DB and I'm going to go ahead
and just build that and once I do that I
can go ahead and say hey just start this
in the beginning so start a sync and in
the end after all the tests are run you
can go ahead and stop it asynchronously
and as you're going to see no container
is running over here we have no running
containers but I can now go up here and
say use
npgsql and I will pass down the
connection string from that container
because it does give me a connection
string as you can see over here it
builds an appropriate connection string
for that database technology and now if
I go ahead and I say run all of my tests
again nothing exist this but now we can
see the container is starting and as you
can see both of my test passed and they
used the real database now for a CI
scenario you have to add this into your
CI pipeline but CI tools support Docker
containers so it is something you can
totally do it's something I've been
doing for the past 3 years already for
my CI as well it works like a charm and
I have reliable integration test but now
I want to know from you do you have any
test related goes like this leave a
comment down below and let me know well
that's all I had for for video thank you
very much for watching and as always
keep coding
Voir Plus de Vidéos Connexes
Film and TV Show Database - Project - Test Your Knowledge
The Pattern You MUST Learn in .NET
GPT-4 Makes Old ChatGPT Look Like a JOKE!
Part3 : Database Testing | How To Test Schema of Database Table | Test Cases
How to test React apps with Vitest and Vite
EntityFramework Core Migrations | ASP.NET CORE | CLI Migrations | Package Manager Console Migratio
5.0 / 5 (0 votes)