What is the best way to write Unit-tests when I'm limited to EF 3.5 entities?
If you're trying to unit test your queries themselves, I would strongly recommend just setting up a test database and testing them with real data. Using IObjectSet<T> in order to substitute an in-memory collection for your unit tests to run against is a BAD idea. There are differences between how a linq query is run under linq-to-objects, and how it's parsed into a T-SQL command, namely in how nulls are handled. For example,
db.People.Where(p => p.AccountNum == variable);
If that's using linq-to-objects (as in some memory object set you've subbed in as a replacement for IObjectSet<T> for your unit tests) then that will run perfectly. If however you're running that against a database, then if variable is null, your query will break, since a query of
WHERE [peopleTableAlias].[AccountNum] = #param1
will be generated, with #param1 being null, which will be worthless, since you really need an IS NULL query generated.
If however you want to test your business logic, which calls your EF datacontext, then I would say to wrap up those queries into DataAccess objects, mark your methods as virtual, inject said DAOs where they're needed, and in your unit tests substitute either manual mocks which override those methods to return the desired value for your tests, or else do the same thing with your favorite mocking framework (ie, Rhino).
EDIT - sorry, IObjectSet<T> is limited to EF4, which you don't have, obviously. But since using that for your unit tests is something I recommended not doing, the answer should still apply.
Related
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.
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
I'm trying to avoid using an in memory database for testing (though I might have to do this if the following is impossible). I'm using NHibernate 3.0 with LINQ. I'd like to be able to mock session.Query<T>() to return some dummy values but I can't since it's an extension method and these are pretty much impossible to test.
Does anyone have any suggestions (other than using an in memory database) for testing session queries with LINQ?
I've tried this before with previous versions of NH without much luck. I eventually used another class to wrap the query and mocked that instead.
I do think it's also worth writing an integration test against a real sql server, to make sure that the repository behaves as expected.
A better approach will be to mock the concept of what you are trying to do, not the inner api of an external system.
For instance
Write the query in a separated artifact, like IQuerySomething / QuerySomething
Test your query against a database. Try this database be prety like the real db.
When testing something that depends on IQuerySomething, mock IQuerySomething.
Fabio Maulo wrote about this pattern as EQO (Enhanced Query Object), i recommend you his post.
This is the way we use in .net for almost everything.
It's looking like you are going to overcomplicate things. I will try to save your time =)
First of all let's start that there is two tipes of testing for the typical project (I am sure you know this, but it is better to mention). Integration tests and Unit tests. And typically (I will assume that you have a typicall application in order no to add "typically" to every sentence) you need both of them.
Integration tests are going on real database and some of them on In-Memory one for better test performance.
So you probably have mappings in your application and want to test them, it is better to do with integration tests on real DB, and if you are using Fluent Nhibernate (if you don't it is better to start using it) this will be a pice of cake.
Then you probably have a kind of Repository or another data access layer (where you are using Linq) that you want to test too. And you probably want to have tests like:
When I submit a query get-customer-by-name, my data access component should return customer with specified name.
This is better to achieve using in-memory database, because this is cheaper. This will save you some time in the typical scenario.
But if you have a lot of complex queries, then I would agree with José F. Romaniello, that it is better to use Enhanced Query Object and test it separately.
You can put your attention on Sharp Arhitecture framework that is targeting a lot of issues when using Nhibernate and testing persistence layer.
public List<int> GetPortfolioList()
{
using (var connection = new SqlConnection("<connectionString>"))
using (var command = new SqlCommand("SELECT * FROM Portfolio", connection))
{
connection.Open();
var portfolioTable = SqlHelper.GetDataTable(command);
var portfolios = from DataRow row
in portfolioTable.Rows
select int.Parse(row["Portfolio"].ToString());
return portfolios.ToList();
}
}
Take this method in a SQL DAL provider to retrieve a list of portfolios, as the name (and code) suggests. Because the database table for integration testing contains a fairly static set of data we can Assert against several expectations. e.g. The list of portfolios will:
- not be empty
- contain certain known values
- contain no duplicates
Following a peer review, someone insisted that this code isn't being properly tested (in isolation) because it relies on database access. In the case that most of the value is found in ensuring that this method returns data from a database whose state is guaranteed, I've been unable to see the value in mocking away the database call in order to write a unit test for this method. Am I missing something?
I'll take the contrary view because I just finished writing a fake db (using in memory lists) to make linq to sql (or linq to anything) unit testable.
This is one question I used to pick a suitable way to fake/mock the database. (from reading your code though, the embedded "SELECT * FROM" means you are leaning on SQL more than linq, which will make it harder to factor your code into stuff that has to be executed by SQL Server and stuff that linq is capable of dealing with.
How are people unit testing code that uses Linq to SQL
I can now run unit tests that will succeed or fail depending on the suitability of my linq query even if the database is unplugged from the wall.
For example, how is your code to react if row["Portfolio"].ToString() is null, how does the code react when this doesn't return any rows, or returns 2?
And even if you are only doing integration tests, nunit is not a bad way to integration tests, just be careful not to call them unit tests, lest a purist get upset about it.
The method uses Linq to project some values from the DB into a list of integers - you may want to test that it does that correctly.
I would split the code into two - the data retrieval and the projection (Linq query) - you could then test the linq query with mock data, without needing to mock the database.
I would also say there is little value in unit testing data access code.
As a testing purist, I believe that I cannot "unit test" a DAL because I cannot do it in isolation. This means that a portion of my code, the one interacting with the database, goes without unit testing. The code above looks fine; just make sure that it exists as part of a larger contract that you can test in other objects.
I do perform integration testing, though, by building a database, seeding it, and ensuring that my DAL works.
I would agree with you, the only value here will be integration testing, there's really nothing to unit test without being pedantic.
The unit test code for any callers of this method should mock this method away, of course.
e: The exception cases MathewMartin mentions above would be the only things I would consider worth unit testing in this scenario.