Get the source code for this video for FREE → the-dotnet-weekly.ck.page/testcontainers Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
This is a great topic! I haven’t finished the video but the one improvement I’d add is to not have credentials hard-coded in the source. Showing the noobs the correct way to implement that would give them a head start on being a better dev that thinks about security.
Hey, thanks, nice video. Would be also nice to have explainations concerning integration tests in deployed DEV and STAGING environments using CI. Thanks for the job done ;)
Thank you for the cool content, This is is really interesting I used SQLite or in memory for my API Tests so far, but this is nice. It would be great, if you can release one video with calling APIs in tests and also apply the migrations to replicate the real scenario
Just came across a few videos of yours regarding testing. Would love if you done more, maybe a dedicated playlist. I see many people talk about integration test for web API’s. But haven’t seen much on integration testing for asynchronous apps (messaging, Kafka etc). Or web apps (ui) - apart from e2e…using web application factory could be useful here also.
Talked about it here: ruclips.net/video/ASa8wXMXwrQ/видео.html However, I still didn't touch on testing a system that uses a message broker. That'd be a great idea for a video.
Great video as always. Just one question does this approach initalize a docker container for each test class or only one container for all test classes?
It's one container per fixture, not the IClassFixture implementation here: ruclips.net/video/tj5ZCtvgXKY/видео.html What does this mean in practice? All tests within a single test class will reuse the same container instances. Test cases from different test classes will have different containers. You can implement an ICollectionFixture, to share containers across all tests within a collection. Or, you can manually create a new container for each test.
Great video Milan! One thing bothers me as I see shadowing methods as a huge red flag and problem causer. I'm just thinking that explicit interface implementation would be much better here. and if not, then why not to override DisposeAsync with line you've put and call to base implementation?
I think this is one of your most helpful videos yet Milan. Given that once you've done the boilerplate to set this up, it's actually pretty easy to write additional tests, would you say this is a good substitute for unit tests as you don't need to mock anything? Or would you still use unit tests alongside this method?
I would definitely prefer this over unit test handlers, yes! I'm also writing a newsletter about this right now, and I'll share all the code on GitHub. P.S. Thanks a lot! I'm working on improving the quality of the videos after releasing my course, and I'm glad it shows.
Thanks for the amazing video. Just a question, how about using an interface in API and then reference it to the test? Something like : public interface IMarker { }
@@MilanJovanovicTech in case of using the partial class in program.cs would it also be possible to include this interface in API project and then reference it to test project? The interface is just a marker and would be empty.
These tests also need something like Respawner library to clear containers db after test execution. Thanks to it a collection of tests can use one container.
Another option is to not put all the tests into the fixture, so it will spin up a container for each test. Of course, this will add overhead and time to your test runs.
@@ВкидимирПодгубенский Maybe. A few things. Linux containers are lightweight and fast. So maybe 30 containers isn't a problem. You only have to isolate db stuff where one test will conflict with another. Another option, write your tests so those data conflicts don't happen. Have each test clean up after itself. Id prefer all these before I bring in some tool to clean the db.
@@MilanJovanovicTech Edit: i just read the document and seems like TestContainers has a wrapper for WireMock but not vice versa. yes. I know they are different tools but can we use one to replace another ?
Great Video, I don't understand how you set up your database structure. Does it do it automatically through the DbContext configuration? If I have foundational data, can I use Entity Framework migrations, or do I need to generate an SQL script for that ?
Great Video. When you perform Build & Test inside Docker containers, using test containers might not work. As Integration tests are already being executed within a container & you want to spin up a container within a container. Any workarounds? Thanks
Great stuff Milan. Had one question is there a way to not use EFCore? I got a project that just uses SqlConnection which calls a store proc and in the settings I am passing only a connection string.
do you have an example video of how to do the DbUp portion of the database? I mean, when it spins up the postgres container, does your image already exist with the schema or is it dynamically running your scripts?
Milan, excellent video, I am just working on this setup so video came in perfect time. I missed one thing. I guess the SQL service in the container pings back when its actually started and that signals the StartAsync to have a successful result? Also, I guess, you do DB migrations up in your Program/Startup logic when the factory goes through. I am asking as I need to do exactly this, migrate up a new instance of DB schema at one point and I guess its is OK in StartAsync after container is spinning? Ideas? Thx!
Hello Milan, thanks for this content. But how do you manage to create the tables automatically in the test container? I tried here and my database couldn't create it. I'm also using migrations.
@@MilanJovanovicTech Of course - managed to do that successfully - I was thinking about structuring of files and versioning, bearing in mind that the TestContainers always points to master DB in the Conn String and regarding SQL SERVER the GO instruction can not be run from remote SQL calls (can not create multiple stored procedures in one statement)
@@MilanJovanovicTech Is there any way for Testcontainers to use your/a docker-compose file rather than having to define the service containers in code which are already defined in your docker-compose file?
Great content as usual, Milan! I think that dispatching commands/queries directly via MediatR shortcuts the WebApi itself - a key part of the application infrastructure. In that sense, it's not a full integration test because you'll not test logic in the HTTP Middleware (such as Auth) or any code sitting in the endpoint handlers that runs before mediatR.Send Would love to see this revisited but using the HttpClient directly to call the API, perhaps including how to (for example) configure the app in testing to expect test bearer tokens.
I'm fine with bypassing the HTTP request pipeline because there is little value in writing a lot of functional tests. A few of them are definitely helpful, but I think having more integration tests like these is beneficial.
I am wondering would not it be possible to share the docker instance among all the tests. Each would create a database and not a whole container to save ressources and reduce the overall test time.
@@MilanJovanovicTech I have been able to do it (with mongo DB using another package to fit my project). I share a singleton using fixture and fixture collection
Thank you Milan for your easy-to-follow videos. Do you have any recommendations for learning best practices in integration tests? For example for "Unit Test" I really like this book: "The Art Of Unit Testing" by ROY OSHEROVE
Will the database in the the docker container have the same schema and data that exist in my physical SQL server database? In my sql server database i have some sql views and functions that i use in my handlers to fetch data.
What about customizing the data inside the container? I see you added a volume, but every test refers to it. Would you tweak them as part of the Arrange section or is there some other strategy you can employ?
There should have already been a scoped service descriptor instance of ApplicationDbContext registered, so how did removing just the options class and re-adding the DbContext to the DI container ever work??
Sometimes to make it faster, they do just make it work. That might be good in a business situation but personally at home I'd prefer finding out how the errors actually work, instead of making it work.
@@MilanJovanovicTech I see. Besides, you can test the controllers in isolation at the same time. One problem I faced with testing API endpoints with test containers is that it fires up a distinct container for each http request even in the same test method so I cannot “get” a database row I just added with a “post” request.
Get the source code for this video for FREE → the-dotnet-weekly.ck.page/testcontainers
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
Finally this day has come! I know once day you will touch this topic. I'm applying this topic on both my side and main projects.
I'm surprised how many people are excited about this topic, you included 😁
Dude, if you ever wrote a book, I got first dibs on it. 😊
The course will have to be enough for now 😅
What should the book be about? 🤔
Man... I got so many comments saying you should use count 1.... Thanks for clearing the doubts.
If it works, it works
This is a great topic! I haven’t finished the video but the one improvement I’d add is to not have credentials hard-coded in the source. Showing the noobs the correct way to implement that would give them a head start on being a better dev that thinks about security.
Where did I hard code them in the source? 🤔
Thanks very much for this. I've always struggled with Integration Testing and this clarified it for me.
Glad it was helpful!
Hey, thanks, nice video. Would be also nice to have explainations concerning integration tests in deployed DEV and STAGING environments using CI. Thanks for the job done ;)
Maybe in a future video, good idea 👌
About time you do this type of video, you need to do more docker work!
Any specific topics?
@@MilanJovanovicTech docker compose, if you think it makes sense to you
Beautiful! Just Beautiful!
Hey, thanks a ton! :)
This is a great resource and had really helped with integration testing. Thank you for your work covering this topic/technology!
Don't mention it!
Thank you for the cool content, This is is really interesting
I used SQLite or in memory for my API Tests so far, but this is nice.
It would be great, if you can release one video with calling APIs in tests and also apply the migrations to replicate the real scenario
Working on a part 2 with more details :)
Great and informative thanks
Glad it was helpful!
Very good thank you. I like the explication about the program class at the beginning. Kind of not necessary but making everything super clear
Sometimes I like to cover all the bases
every video is mind blowing
That's a high standard to live up to 😅
Hey Milan great video, thanks! Is there a way to use the testcontainers package with a CosmosDB? 🙂
Can you run it from Docker?
Great stuff, Milan. Why not use Selenium IDE for running your web tests (alongside Docker for setting up your infrastructure)?
I don't typically write automated UI tests
Just came across a few videos of yours regarding testing. Would love if you done more, maybe a dedicated playlist.
I see many people talk about integration test for web API’s. But haven’t seen much on integration testing for asynchronous apps (messaging, Kafka etc). Or web apps (ui) - apart from e2e…using web application factory could be useful here also.
Talked about it here: ruclips.net/video/ASa8wXMXwrQ/видео.html
However, I still didn't touch on testing a system that uses a message broker. That'd be a great idea for a video.
Excellent video!
Thank you very much!
Great video as always. Just one question does this approach initalize a docker container for each test class or only one container for all test classes?
It's one container per fixture, not the IClassFixture implementation here: ruclips.net/video/tj5ZCtvgXKY/видео.html
What does this mean in practice? All tests within a single test class will reuse the same container instances.
Test cases from different test classes will have different containers.
You can implement an ICollectionFixture, to share containers across all tests within a collection.
Or, you can manually create a new container for each test.
Great video Milan!
One thing bothers me as I see shadowing methods as a huge red flag and problem causer.
I'm just thinking that explicit interface implementation would be much better here. and if not, then why not to override DisposeAsync with line you've put and call to base implementation?
Given this is a test class, I think the decision was justified for simplicity. For a more correct solution, your approach is fine 👌
I think this is one of your most helpful videos yet Milan. Given that once you've done the boilerplate to set this up, it's actually pretty easy to write additional tests, would you say this is a good substitute for unit tests as you don't need to mock anything? Or would you still use unit tests alongside this method?
I would definitely prefer this over unit test handlers, yes! I'm also writing a newsletter about this right now, and I'll share all the code on GitHub.
P.S. Thanks a lot! I'm working on improving the quality of the videos after releasing my course, and I'm glad it shows.
How does this work without running the migrations on the docker database?
Migrations are executed at startup in Program, omitted that part
Thanks for the amazing video.
Just a question, how about using an interface in API and then reference it to the test?
Something like :
public interface IMarker { }
What would the interface be for?
@@MilanJovanovicTech in case of using the partial class in program.cs would it also be possible to include this interface in API project and then reference it to test project?
The interface is just a marker and would be empty.
These tests also need something like Respawner library to clear containers db after test execution. Thanks to it a collection of tests can use one container.
Another option is to not put all the tests into the fixture, so it will spin up a container for each test. Of course, this will add overhead and time to your test runs.
@@pilotboba no way , if there are 30 tests - it will start 30 containers!
@@ВкидимирПодгубенский Maybe. A few things.
Linux containers are lightweight and fast. So maybe 30 containers isn't a problem.
You only have to isolate db stuff where one test will conflict with another.
Another option, write your tests so those data conflicts don't happen. Have each test clean up after itself.
Id prefer all these before I bring in some tool to clean the db.
What if each test handles its own data?
@@MilanJovanovicTech every test manages it's data and clear it after execution using Respawner
Thanks for the content.
I have a question : what are the Pros and Cons when using TestContainer over the WireMock ?
WireMock is for API mocking (HTTP) right?
@@MilanJovanovicTech
Edit: i just read the document and seems like TestContainers has a wrapper for WireMock but not vice versa.
yes. I know they are different tools but can we use one to replace another ?
Great Video, I don't understand how you set up your database structure. Does it do it automatically through the DbContext configuration? If I have foundational data, can I use Entity Framework migrations, or do I need to generate an SQL script for that ?
I run EF migrations at startup (web app factory setup).
@@MilanJovanovicTech so do you run it after you start async right or how you do it ?
I think is the config that starts at minute 5:30 of the video.
Great Video.
When you perform Build & Test inside Docker containers, using test containers might not work.
As Integration tests are already being executed within a container & you want to spin up a container within a container.
Any workarounds?
Thanks
Containerception. What environment would you be running that in?
@@MilanJovanovicTech Say, Azure DevOps or a Self hosted Kubernetes Cluster
Great stuff Milan. Had one question is there a way to not use EFCore? I got a project that just uses SqlConnection which calls a store proc and in the settings I am passing only a connection string.
Sure, why not? Just write some good ol' SQL 😁 Dapper is a good choice.
do you have an example video of how to do the DbUp portion of the database? I mean, when it spins up the postgres container, does your image already exist with the schema or is it dynamically running your scripts?
Migrations are ran when app starts in this case. Might be a good idea for a video.
Is there a way to specify the build configuration for the container using appsettings?
Can you be more specific? 🤔
@@MilanJovanovicTech For example the parameters for WithDatabase() WithUsername() WithPassword() I want to get from appsettings.
Milan, excellent video, I am just working on this setup so video came in perfect time. I missed one thing. I guess the SQL service in the container pings back when its actually started and that signals the StartAsync to have a successful result? Also, I guess, you do DB migrations up in your Program/Startup logic when the factory goes through. I am asking as I need to do exactly this, migrate up a new instance of DB schema at one point and I guess its is OK in StartAsync after container is spinning? Ideas? Thx!
Yeah, creating DB is done in Program, I omitted that.
@@MilanJovanovicTech Is it possible to do a full video on how you created the db schema inside your container?
@@TheDrComedy That would be super nice
Hello Milan, thanks for this content. But how do you manage to create the tables automatically in the test container? I tried here and my database couldn't create it. I'm also using migrations.
Run migrations at startup
How would you approach schema creation and seeding in an app that doesn't use EF (repositories execute raw SQL or stored procedura) ?
Just run some SQL
@@MilanJovanovicTech Of course - managed to do that successfully - I was thinking about structuring of files and versioning, bearing in mind that the TestContainers always points to master DB in the Conn String and regarding SQL SERVER the GO instruction can not be run from remote SQL calls (can not create multiple stored procedures in one statement)
@@MilanJovanovicTech Is there any way for Testcontainers to use your/a docker-compose file rather than having to define the service containers in code which are already defined in your docker-compose file?
can you containerize the api itself for e2e testing? where you can still debug it..
How will you hook into it for debugging? I'm not sure that's supported during test execution
Thank you!
You're welcome!
Great content as usual, Milan!
I think that dispatching commands/queries directly via MediatR shortcuts the WebApi itself - a key part of the application infrastructure. In that sense, it's not a full integration test because you'll not test logic in the HTTP Middleware (such as Auth) or any code sitting in the endpoint handlers that runs before mediatR.Send
Would love to see this revisited but using the HttpClient directly to call the API, perhaps including how to (for example) configure the app in testing to expect test bearer tokens.
I'm fine with bypassing the HTTP request pipeline because there is little value in writing a lot of functional tests. A few of them are definitely helpful, but I think having more integration tests like these is beneficial.
I am wondering would not it be possible to share the docker instance among all the tests. Each would create a database and not a whole container to save ressources and reduce the overall test time.
That's a great point. Let me try to find some resources around that
It's possible if use Respawner library and clear db after each test
@@MilanJovanovicTech I have been able to do it (with mongo DB using another package to fit my project). I share a singleton using fixture and fixture collection
@@porcinetdu6944 fixture collection creates a singleton?
Thank you Milan for your easy-to-follow videos. Do you have any recommendations for learning best practices in integration tests?
For example for "Unit Test" I really like this book: "The Art Of Unit Testing" by ROY OSHEROVE
There could be a book like that, but I haven't read it yet, so can't recommend anything
Will the database in the the docker container have the same schema and data that exist in my physical SQL server database?
In my sql server database i have some sql views and functions that i use in my handlers to fetch data.
Yes, if you recreate that structure with migration scripts
What about customizing the data inside the container? I see you added a volume, but every test refers to it. Would you tweak them as part of the Arrange section or is there some other strategy you can employ?
Test container is separate from my docker compose ond
@@MilanJovanovicTech ah I see, makes sense.
There should have already been a scoped service descriptor instance of ApplicationDbContext registered, so how did removing just the options class and re-adding the DbContext to the DI container ever work??
Grab the source code below and give it a try.
The options are what actually configures the important bits.
Sometimes to make it faster, they do just make it work. That might be good in a business situation but personally at home I'd prefer finding out how the errors actually work, instead of making it work.
Why don't you test against API endpoints instead of Service methods?
Simpler
@@MilanJovanovicTech I see. Besides, you can test the controllers in isolation at the same time.
One problem I faced with testing API endpoints with test containers is that it fires up a distinct container for each http request even in the same test method so I cannot “get” a database row I just added with a “post” request.
Are the migrations automatically applied to the container? (Only question I have)
Yes (at app startup)
@@MilanJovanovicTech Thank you 😊
What is the difference between minimal api approach and api with controllers in 3:45? How should I do that with controllers?
Well Program.cs is already public there?
no difference - just write this line in your program.cs
@@MilanJovanovicTech Not if you use top level statements with controllers. You still need to add the partial public visible class afaik.
Why should i use temporary database if i just could use Moq to mock the database. No need to spin up anything. :)
Because you might as well be using in-memory data. Why even have a database?
@@MilanJovanovicTech yeah. That was my idea but tests are calling methods that have db queries inside. Those should be mocked as well.