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.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top