DbContext Unit Testing

I learned some information about the methods that I could use for the unit test DbContext . I would like to add some data in memory to the context so that my tests can work against it. I am using the Database-First approach.

The two articles I found most useful were this and this . This approach is based on creating the IContext interface, which will be implemented by both MyContext and FakeContext, allowing a Mock context.

However, I try to avoid using repositories for abstract EF, as several people have pointed out , since EF 4.1 already implements the repository and unit of work patterns through DbSet and DbContext, and I really would like to keep all the functions implemented by EF Team without having to support them with shared storage, as I did in another project (and it was painful).

Working with IContext will lead me to the same path (or right?).

I was thinking of creating a FakeContext that inherits from the main MyContext and thus uses the DbContext under it to run my tests without getting into the database. I could not find such implementations, so I hope someone can help me with this.

Am I doing something wrong, or can it lead me to some problems that I do not expect?

+48
Jul 20 '11 at 18:14
source share
5 answers

Ask yourself one question: what are you going to test?

You mentioned FakeContext and are mocking the context - why use both? These are just different ways to do the same thing - provide only a test implementation of the context.

There is another big problem - falsification or a mocking context or set has only one result: you are no longer testing your real code.

A simple example:

 public interface IContext : IDisposable { IDbSet<MyEntity> MyEntities { get; } } public class MyEntity { public int Id { get; set; } public string Path { get; set; } } public class MyService { private bool MyVerySpecialNetMethod(e) { return File.Exists(e.Path); } public IEnumerable<MyEntity> GetMyEntities() { using (IContext context = CreateContext()) { return context.MyEntities .Where(e => MyVerySpecialNetMethod(e)) .Select(e) .ToList(); } } } 

Now imagine that this is in your SUT (the system is under testing - in the case of unit test it is unit = usually a method). In the test code, you provide FakeContext and FakeSet , and it will work - you will have a green test. Now in the production code, you will provide another DbContext and DbSet , and you will get an exception at runtime.

Why? Because, using FakeContext , you also changed the LINQ provider, and instead of LINQ to Entities you use LINQ to Objects, so you call local .NET methods that cannot be converted to SQL, as well as many other LINQ functions that are not available in LINQ to entities ! There are other problems that you may find with changing data: referential integrity, cascading deletes, etc. That is why I believe that the code associated with the / LINQ to Entities context should be covered by integration tests and executed with a real database.

+31
Jul 20 2018-11-21T00:
source share
β€” -

As in EF 4.3, you can unit test your code by entering a fake DefaultConnectionFactory before creating the context.

+12
Aug 12 2018-12-12T00:
source share

I am developing an open source library to solve this problem.

http://effort.codeplex.com

Little teaser:

You do not need to add any template code, just call the appropriate library API, for example:

 var context = Effort.ObjectContextFactory.CreateTransient<MyContext>(); 

At first, this may seem magical, but the created ObjectContext will contact the database in memory and will not talk to the original real database at all. The term "transitional" refers to the life cycle of this database, it only lives if the created ObjectContext is created. At the same time, created ObjectContext objects exchange data with selected database instances; data is not transmitted through them. This makes it easy to write automated tests.

The library provides various functions for setting up creation: exchange data between instances, set initial data in a database, create a fake database at different data levels ... check the site for more information.

+11
Jan 29 '13 at 13:48 on
source share

Entity Framework 4.1 is close to being up to date with tests, but requires a little extra effort. The T4 template provides you with a DbContext derived class that contains DbSet properties. Two things that I think you need to make fun of are DbSet objects that return these properties and their properties and methods used in the DbContext derived class. Both can be achieved by modifying the T4 template.

Brent Mackendrick showed the types of modifications that should be made in this post , but not the modifications to the T4 template that can do this. About:

  • Converting DbSet properties into a derived DbContext class into IDbSet properties.
  • Add a section that generates an interface for the DbContext derived class containing the IDbSet properties and any other methods (such as SaveChanges) that you need to make fun of.
  • Implement a new interface in the DbContext derived class.
+5
Oct 18 '11 at 6:22
source share

For those who are still looking for answers - I wrote a simple library to ease the mockery of DbContext in a very simple way. See my other answer to SO for a similar question for more details : https://stackoverflow.com/a/166189/

PS I agree with what Ladislav Mrnka says, however I think that in some cases it is inevitable that you need to make fun of your DbSet and run unit tests against it. Although you need to keep in mind that you should not test your LINQ queries to see if they returned the correct data. That integration tests are more applicable.
+1
Nov 15 '15 at 4:15
source share



All Articles