Currently i am refactoring test for my context methods to not need a real database anymore. I use Ef Core.
So i read through the Microsoft documentation how to test context methods. I found the documentation for EF6 testing first and read the one for EfCore after.
Here are the links:
Ef Core Testing
Ef 6 Testing
What i found interesting is that there are different best practices for EF6 and EF Core.
For EF6 Microsoft advises to use Mocking contexts with Moq or writing own test doubles.
So both times mocking the context.
For EF Core Microsoft advises to use Sqlite or the built in InMemory database.
Mocking the context with Moq seems pretty reasonably for me. I just want to test the functionality of the methods. I have to do integration test anyways afterwards. Why is it not in the recommended ways for EF Core anymore?
And more generally what are the advantages or problems with the different methods?
Take a closer look at the following quote from the same article...
SQLite in-memory mode allows you to write efficient tests against a provider that behaves like a relational database.
This provides you with constant and non changing test data but also the relational database problems and behaviors. It's much closer to the actual real life scenarios.
Mocking on the other hand provides you with an implementation where you can change the relational to any other model, thus it is much more versatile.
Since EF is for db and you are making tests for EF, then it makes perfect sense to go with the first option. More often than not you will not even need to test trivial operations like genetic repositories, e.t.c.
Make sure that when testing on a higher level (classes that consume repositories and such) you use mocking, as you want to mock interfaces which have no and should not have any coupling with the concrete implementations.
Related
I'm trying to reduce the startup time for tests against an EF 6x datastore. The tests are within a transaction and the db gets rolled back once done. I would appreciate any suggestions on how to retain an instance of the DbContext between test sessions so that EF doesn't have to go through the whole view generation process again?
I don't want to use mocks/fakes, non-Microsoft branch of EF and interactive views are already in place. Thank you.
Different options. As you did not mentioned your aim of testing and there is not any code, the options are:
If you are inserting many records into your tables, you can do a bulk insert. The best library for doing this is:EntityFramework.BulkInsert-ef6. You can install it through Nuget console.
If you see slowness while working with data and you have many load/manipulation/save operations, you have to do in-memory operation as Sampath recommends.
If you are loading data, just load the columns that you need. You also should use lazy loading option(which from your post, I think you know it well).
4.Some portion of the slowness could be because of the architecture of your database. The key column types have a considerable effect on Where operations!
I would like to recommend you to use in-memory data for that. I am also used this pattern and it is really well and very fast. This is the pattern where the industry recommended and trouble free in long run. Always try to use best practices when you develop a software app.
When writing tests for your application it is often desirable to avoid
hitting the database. Entity Framework allows you to achieve this by
creating a context – with behavior defined by your tests – that makes
use of in-memory data.
Here is the article about how to do that :Testing with a mocking framework
Another article for you : Unit testing in C# using xUnit, Entity Framework, Effort and ASP.NET Boilerplate
I have a method like this in my repository layer:
public IEnumerable<User> GetActiveUsers()
{
return dbContext.Users
.Where(u => u.IsActive)
.OrderBy(u => u.Name)
.ToList();
}
Should I unit test this method by mocking the DbContext or should I test it with an actual database?
I know it stops being a "unit" test when I use an actual database, but I don't see the value in mocking the DbContext to test my repository methods which are thin in logic and usually just calls EF's method directly.
And if I have to use an actual database, is there any standard strategy to populate test data in the database so tests run independently and do not alter any state in the database?
Probably not what you want to hear, but you don't want to mock DbContext. I know it's been done all the time and in EF6 it's even been made easier than before. There are yet more interfaces and virtual methods available to implement mock objects. Technically it's not hard.
It's the behavior that matters.
Even in your small example there is a possible catch. A mock DbSet would do case-sensitive sorting. A connected DbSet would receive sorted data from the database and many database collations happen to be case-insensitive. So a unit test could produce different results than an integration test, even in this seemingly insignificant case.
The differences between in-memory and connected LINQ are overwhelming. Personally, I do only integration tests for anything that involves any LINQ to Entities query. It's just too easy to create a mock object graph that would look different if EF would have built it. In my service methods I sometimes compose pretty complex queries, maybe involving Includes, maybe deliberately omitting null guards, knowing that the statement is translated into SQL, maybe involving some lazy loading or relying on relationship fixup. I have to be aware of entity states, context lifespans, validation that kicks in when saving changes, concurrency ... I just don't believe green tests when it's all mocked.
Of course there's enough business logic left to test with pure unit test. Once you can make the assumption that correct objects are available (because you test that separately in integration tests) you can mock them and unit test their behavior in-memory.
On the other hand: what additional information would you get by setting up a database and testing against that?
I would simply mock the DbContext because it will be easiest to maintain and because there is no value in essentially unit testing the Entity-Framework's calls against a database.
The thing you want to be testing is whether or not your LINQ queries return the data from the datasource. However those LINQ queries are translated to SQL queries by EF is something you won't bother with.
You can consider it as an additional integration test if you really want to test your external dependencies but EF by itself is already very reliable so I doubt that this would be useful in any way.
If IEnumerable GetActiveUsers is implemented (and it should) as an interface, and the code you posted is a concrete class which implement the interface. Then you would normally use the mock framework to mock the interface you implement and return a result set you set up.
As Jeroen mentioned, you normally don't need to unit test what entity framework doing. Unit test is only test your logic, not the other library (EF here) logic.
Something to keep in mind when writing a Mock for your DBContext and executing your LINQ Queries is that they are running against the mock context object as LINQ to OBJECTs, not LINQ to Entities... (EF6)...
I personally would put your time into testing the behaviors. Julie Lerman has a series # pluralsight and MSDN Mag online covering how to test the dbContext if you must.
Since MSDN says about DbContext:
A DbContext instance represents a combination of the Unit Of Work and
Repository patterns such that it can be used to query from a database
and group together changes that will then be written back to the store
as a unit. DbContext is conceptually similar to ObjectContext.
Is it not redundant to implement these two (Unit of Work & Repository) when using EF5+?
Can somebody shed more light on this subject?
I intend to build an MVC based application using SQL server and after reading a lot about data access techniques with unit testability, I am kind of lost with the above info!
That depends on the complexity of your project and its requirements. For instance, these two questions might help your decision making:
Will you use any other data sources besides EF that must work along it?
How likely it is that you swap EF for a different ORM or data source in the future?
If you can't foresee changes or you don't need to work with more than just EF then it's probably not worth the trouble.
I would create a Generic repository so you can mock it in your tests more easily than mocking Entity Framework's context directly. But, yes, EF 5+ does implement these patterns as MSDN states.
It's a layer of abstraction. The repository pattern is a collection of objects and a thing to get a collection of objects. Entity Framework knows HOW to get that collection of objects, the repository does not know HOW.
Entity Framework has a lot features that you potentially loose by wrapping it in a repository or a thinner service. If you practise TDD coding against your own classes is often more comfortable than mocking third-party code.
Ayende has a blog post about this.
I'm trying to test my code using EntityFramework code first. In order to make it testable and to allow isolation testing, I created an interface which my DbContext implements. I'm not testing the DbContext class - I'm going to assume EF code works as expected.
Now, consider the following method:
public IEnumerable<User> GetOddId()
{
return context_.Users.Where((u, i) => i % 2 == 1).AsEnumerable();
}
This method will pass with my mock FakeDbSet (because it would use the in-memory LINQ provider) whereas it would fail with an Exception when using the EF/LINQ to SQL drivers.
Would you leave it as it is and hope people know enough not to write such queries? Would you give up isolation testing and test on an actual db?
Would the LocalDb with DataMigrations (perhaps with appropriate seeds) help with testing on an actual db?
Please justify the answer(s).
TLDR: How to test EntityFramework code, considering the differences between in-memory LINQ and SQL LINQ?
Much later edit: I've since found a very good framework that does exactly what I need. I wrote a blog post about unit testing with Effort. Also please note all this might not be needed in the upcoming EF6, which promises a some unit testing features.
We use SQLite's in-memory databases for this purpose. They are extremely quick to create, query and tear down and barely have any impact on overall test speed. Once you've set yourself up a test framework to create a database and inject data, tests are quick to write.
Of course, SQLite is a much simpler database than most, so complex queries may fail to translate to its version of SQL, but for testing 90% of cases, it works well.
Do these tests constitute integration tests? I don't think so. They are still only testing one unit of your code, namely the bit that generates a LINQ query. You're testing for two things: 1) that the query returns the correct data (but you could check this using an in-memory collection as you stated), and 2) that the query can be translated into valid SQL by Entity Framework. The only real way to test the latter is to fire the query at a real Entity Framework but with a stubbed database.
Whilst you could argue that a true unit test should test just the output of your code (i.e. parse and check the expression tree that has been generated), as well as being harder to write, it doesn't really prove anything. If, for example, you modify the code to generate an inner join instead of a subquery, would you want the test to break? Only if it returns different results, I would have thought.
Where I work, we have a dev/beta/production SQL server. Sometimes we'll create tests against beta and seed test data (e.g. insert before testing specific selects and such) before executing tests on an actual database. People will draw a distinction between unit and integration testing, but it at least lets us test our logic, which is better than just crossing fingers and hoping for the best at the data-access layer.
What good is an in-memory provider that's easy to test for but doesn't actually represent the live system in some important cases?
EDIT: We don't use EF, btw...
You might want to use a mocking framework like Telerik's JustMock (or choose from many others).
This would give you lots of control over what happens in your test code. (Short introduction here.)
Instead of implementing a query to a real database you could 'simulate' the query and return a pre-defined collection of objects.
You could, for example, create multiple unit tests that call your GetOddId() method, and define different return collections that cover all the test cases you need (an empty list, correct content, wrong contents, throwing an exception, whatever, ...).
There is also a free 'Lite' version here or via NuGet.
I have been doing a lot of unit testing lately with mocking. The one thing that strikes me as a bit of a problem are the differences between querying against an in memory list (via a mock of my repository) and querying directly against the database via entity framework.
Some of these situations might be:
Testing a filter parameter which would be case insensitive against a database but case sensitive
against an in memory collection leading to a false fail.
Linq statements that might pass against an in memory collection but would fail against entity framework because they arent supported leading to a false pass.
What is the correct way to handle or account for these differences so that there are not false passes or fails in tests? I really like mocking as it makes things so much quicker and easier to test. But it seems to me that the only way to get a really accurate test would be to just test against a the entity framework/database environment.
Besides the unit tests you do you should also create integration tests which run against a real database setup as encountered in production.
I'm not an expert for EF but with NHibernate for example you can create a configuration which points to an in-memory instance of SQLite where you then run your quick tests against (i.e. during a development cycle where you want to get through the test suite as fast as possible). When you want to run your integration tests against a real database you simply change the NHibernate config to point to a real database setup and run the same tests again.
Would be surprising if you could not achieve something similar with EF.
You can use DevMagicFake, this framework will fake the DB for you and can also generate data so you can test your application without testing the DB
First and most important is you can define any behavior data within your mock. Second is speed. From unit testing perspective testing speed counts. Database connections are bottleneck most of time so that's why you mock it with tests.
To implement testing properly you need to work on your overall arch first.
For instance to access data layer I use repository pattern sometimes. It's described really good in Eric Evans DDD book.
So let's say if your repository is defined as below
interface IRepository: IQueryable, ICollection
you can handle linq queries pretty straightforward.
Further reading Repository
I would make my mocks more granular, so that you don't actually query against a larger set in a mock repository.
I typically have setters on my mock repository that I set in each test to control the output of the mocked repository.
This way you don't have to rely on writing queries against a generic mock, and your focus can be on testing the logic in the method under test