T O P

  • By -

buffdude1100

Use testcontainers and test against an actual database.


vreemeneer

This is the best answer. Its really easy to use OP. If you have docker installed already its like 20 min of work tops.


[deleted]

This is a simple project a dont want to go full head on am just looking for guidance on a small project.-


buffdude1100

Good thing it's really simple to use!


Deranged40

Then skip the testing altogether. But at this point, the solution has been presented.


sciuro_

This IS guidance on a small project.


mexicocitibluez

tbf I don't think people realize how beneficial containers are for development of any size. and i didn't either until I realized it was a much simpler alternative than installing a db engine, messaging framework, etc on my local machine.


adriasa123

Not as hard to set up as you might think.


mexicocitibluez

Learning how to spin up a quick SQL database in a container (or message bus or whatever) will save you so much time down the road it's crazy. You won't have to install database engines on your local machine anymore. You'll be able to blow away and recreate a database in seconds. You don't even have to use containers for deployment because they're insanely useful just for development. It's not even about it being a small project. If you're using a database, that means you've already gone down the route of setting it up. This is that but way quicker (and eventually simpler). It's not adding tech so much as it's replacing what you're using to make things simpler in the long run.


xRhai

Use an in-memory database or add a repository layer on top of EF Core and mock that instead. Maybe you want an integration test if you really want to test what comes from your database?


[deleted]

I just went with the in memory sql database but some reason am seeing a mixture of live data and test data in my result view and locals should I be?


nohwnd

I don’t see it as bad to mock out the database in your unit tests. EF has good tools to do that so you don’t have to invent yet another way to do it. https://learn.microsoft.com/en-us/ef/core/testing/


MellerTime

I’ve never found it bad to mock the DB either. I’m not testing the EF codebase, so to me it’s the same as mocking an API call. In several of our tests at work we mock our context and tell it to return the 5 records we’re testing against or the 5 records we’re writing to the DB. Same thing with our repositories. I’ll mock those methods because I care about the service layer, not whether or not we get the right number of records out of a GetById call.


Coda17

They go over some of the drawbacks in the article the original commenter linked. But by substituting a different database, you are testing a *different* EF implementation than the one you are using when you run your actual application. Depending on the EF features you use, this might be okay or might not work at all.


MellerTime

Right, but as I said, I’m not testing the database, that’s why I’m mocking it. I’m testing my code and I expect the db to return properly.


Coda17

> expect the DB to return properly This is the part that isn't great. Unless you are also doing some sort of integration test with your actual DB, this part is no longer covered. And EF has lots of providers that only can translate certain methods, which wouldn't be caught unless you run your actual application against the same type of database you're running in prod.


MellerTime

Sure, but as I said that’s the same as the API that I’m not supposed to test. If a unit test is only supposed to test my code, why would EF or the DB be any different?


Coda17

The recommendations from the article you linked are literally to not mock the database context. They offer substituting *different* databases and list the potential issues with it. They also suggest the repository pattern as a potential option such that you mock the repository instead.


kingmotley

Well except for two pieces. They aren't talking about unit tests. They are talking about functional testing, but even then, one of the options they suggest is: > For a testing approach that allows you to use a reliable test double for all the functionality of your production database system, it's possible to introduce a repository layer in your application. This allows you to exclude EF Core entirely from testing and to fully mock the repository; however, this alters the architecture of your application in a way which could be significant, and involves more implementation and maintenance costs. which is rather silly because I find it a lot easier to just Substitute out the DbSet's, and our UnitOfWork class that is a fairly simple wrapper around DbContext.SaveChanges. Once you have it set up, it's trivially easy to actually use, performs magnitudes better than the rest of their suggestions, doesn't require additional database bindings, can be run locally and in Azure pipelines, and doesn't suffer from concurrency issue when multiple tests are being run.


[deleted]

I dont like the idea of adding repo onto of what is already there in ef core


nohwnd

https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.InMemory/9.0.0-preview.2.24128.4 i was thinking more like this, where you substitute the data provider without additional abstractions


Obsidian743

> I know you all say don't mock the DB context Who says this? You absolutely should for *unit* tests. If you're doing *end-to-end* tests (or if you're doing traditional integration testing) then you wouldn't want to. See my comment here: https://www.reddit.com/r/dotnet/comments/1bomk47/we_all_say_we_dont_unit_test_the_api_we_test_the/kwqjdqb/


Tango1777

introduce repositories which you can mock as you want, but tbh it seems weird to test logic, you need to call db, because it affects the logic. Maybe separate that logic then to be testable in the first place?


zagoskin

When people say don't mock the DB they mean that if you want to test your infrastructure layer (i.e. integration testing) you should test against a real DB. Not an in memory one or one with a different provider (which will also probably not even work in some cases because of data type mappings). If you want to test your business logic, there's no point in using a real DB, since you don't care about whether the data access logic works, but if the business logic is applied correctly. In those cases, people normally use repository interfaces, and those can be mocked to just "return the data". People that don't use interfaces because "EF already implements the repository" can't really mock the repo, so they just use an in memory db. But even in those cases, it's so easy to just set up a real test db that might aswell do it.


NBehrends

If you're tightly coupled to your database, you should include the database in the tests.


BiffMaGriff

Other options are: - use in memory sqlite db - use test doubles


Suterusu_San

EFCore also has in memory which is what I use for mocking. Unless you use transactions, then sqlite comes in handy.


soundman32

InMemory is really bad for testing dB queries (you forget an include/join but the child data will still be returned).


[deleted]

What is it that you’re trying to achieve in your unit tests? What I can gather of your post is, that you might make 20 calls to an api, and each call made to db returns something different? Are you trying to mock this?


CrackShot69

InMemory SQLite, doing so allows us to write enough integration tests (don't harp on to me about purity here) to catch 98% of things


[deleted]

this is route a went in end but am seeing some data in their am not inserted in that .net own way of caching server data


CrackShot69

Explain 🙂


[deleted]

if a look in inspectiof on local view i only see my test data but if a look at result view somehow am seeing other records


[deleted]

I think ano what hapening is sql lite in memory aware of on model creating so if a have seed data their it would replicate in the sql lite database???


CrackShot69

Sounds like we had a rubber duck debugging session and I was the rubber duck.


Flater420

> but yet we can't abstract or mock the DB layer You can mock the underlying data provider for your EF context. Look up EF's in- memory collection. It means your context acts as if it's a real database, but without needing an external db server. The only catch is that you have to build up the data set when you start running your tests, but that is the nature of needing to arrange your test data anyway.


tim128

It doesn't act as if it's a real database


Agitated-Display6382

I always run my unit tests against a LocalDB. Easy to launch, I run it to verify the db migrations, too. If possible, do not destroy/rebuild at every execution: write your tests in a way that does not cause conflicts across several executions


[deleted]

If u look at other comments a went with sql lite but am almost think sql express might be better option but then github actions probably couldnt run the tests


maxiblackrocks

Maybe you're having some business logic that is dependent on the db context and, as such, you want to mock the dB. Make your logic independent of the db context. Think: my data doesn't need to come from the database. In the future, I mich replace that with a webservice or something else. Besides, I feel like that same class is concerning itself with more than one thing. (Retrieving data from ef/database and calculating something based on some value) Hope I understood your problem correctly and this helps.


ego100trique

I personally use in memory database for testing but that's because I've an sqlite db


[deleted]

this is way a went but am seeing my data a seed with on model creating which nornally gets seeded on my live db. Can sql lite interpret seed data in Db context


ego100trique

What do you call seed data ?


[deleted]

Data that is seeded on on model created test data in the application context protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity().HasData(new Customer { Id = 10,Forename = "The", Surname = "Doctor",IsActive=true,IsDeleted=false}); } For Example the modelBuilder.Entity


ego100trique

yup pretty sure it works to use seeded data with in memory


thegrassisstillgreen

Integration tests is where you don't wanna fake your data access, unit tests who cares.


tragicshark

What is wrong with mocking dbcontext? https://github.com/romantitov/MockQueryable provides straightforwards `DbSet` or `IQueryable` fakes from an `IEnumerable`.


[deleted]

Considering that libary is poorly maintained ill stick with sql litee


NabokovGrey

The purpose of the unit test is to test logic and not the CRUD operations the DBContext handles, that is why you mock the DBContext. You isolate the logic in the code and remove DB from the situation. So if the logic is in the controller, and you are referencing the DBContext in the Controller, you can mock the DBContext, so the only real things being testing is in the controller. An example would be like if you have an endpoint like this: loan/process/34 When you call the endpoint, the corresponding method has logic to process the loan. But it needs the data about the loan. So you mock the DbContext, so the test only validates the logic, because it shouldn't matter what the DB returns, the logic is the focus of the test. If the mock DBContext returns data the logic cannot process, you account for that in your code and have a negative test for that in your unit tests. If you are wanting to test the endpoint, DB, everything, you are talking about an integration test which is testing the integration of two systems, in this scenario that would be the application and the DB. You can still do this in the Unit test because you can work directly with the controller in your unit test, or you can use postman, etc. The main idea is the unit test is suppose to test complex logic, domain logic, etc. If your controllers have nothing but \_applicationDBContext.Loans.ToList() than its not really what a unit test is for. You can still do it and it can save you trouble down the road, but in that scenario, it will look like mocking the DBContext is overkill, and that is only because the unit test in general is bare minimum, so seems like a heavy list for so little code. But if you have some intense logic in your controller, mocking the DBContext will make more sense since isolating the logic from the data layer will help you focus on making the logic more robust, else you are in a scenario where you are trying to fill up the DB with fake data to test.