Unit testing with Entity Framework
Asked Answered
S

13

71

I want to test my Entities that are built using Entity Framework. My concern is that using Entity Framework means directly working with data source. So any ideas how to unit testing Entity Framework based components?

Salivation answered 28/11, 2008 at 19:1 Comment(1)
Possible duplicate of How are people unit testing with Entity Framework 6, should you bother?Boult
D
50

For Enity Framework 4, this looks promising: Testability and Entity Framework 4.0

Danaedanaher answered 9/6, 2010 at 9:30 Comment(3)
Going to read that now. A lot of the EF testing Questions and answers aren't up to date, so +1 for EF 4.0 link.Cleome
Our shop is starting to implement the techniques seen here, and it seems like the answer so far.Phenylketonuria
FYI, he never disposes the context in the UnitOfWork classes. In this example, asp.net/entity-framework/tutorials/…, the UnitOfWork class implements IDisposable. Combine the two approaches and decorate the IUnitOfWork interface in Hans's answer with IDisposible and implement the Dispose pattern e.g. msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.71).aspxPicrotoxin
B
7

Apparently it's very hard. Eloquently put by Erik here - TDD and ADO.NET Entity Framework

Brinkman answered 28/11, 2008 at 22:28 Comment(0)
P
6

A cheap approach is to set up a database file with the same structure as your real database and set the connection string in your unit test config to point to that. The database doesn't need to have all of the tables that the real one has; just the ones the unit test needs.

A disadvantage is that you need to manage the state of the database so that unit tests don't impact each other or themselves during and between runs.

I know this approach works when both the real and unit testing DBs use SQL Express but I don't know about stubbing in a SqlExpress DB for a full SQL DB.

I realize this is technically integration testing, but it could be cheaper than refactoring your code or learning a mocking framework.

Example real connection string:

<add name="DrinksEntities" 
     connectionString="metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient
     ;provider connection string=&quot;Data Source=localhost\sqlexpress;Initial Catalog=Drinks2;Integrated Security=True;MultipleActiveResultSets=True;Application Name=EntityFramework&quot;" 
     providerName="System.Data.EntityClient" />

Example unit testing connection string:

<add name="DrinksEntities" 
     connectionString="metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient
     ;provider connection string=&quot;Data Source=.\SQLEXPRESS;attachdbfilename=|DataDirectory|\Inventory.mdf;Integrated Security=True;user instance=True;MultipleActiveResultSets=True;Application Name=EntityFramework&quot;" 
     providerName="System.Data.EntityClient" />
Picrotoxin answered 22/10, 2011 at 16:35 Comment(3)
So far, this looks the best solution to me. Run the entire database in RAM if you want to speed it up. These are end-to-end tests. The mocking solutions are no solution at all. The point of testing the database is not only to test persistent storage but to test queries. A query test only makes sense when it's actually exercised - mocking is a pure waste of time here - you need fake table data. I tried creating an entire set of fake repositories for Linq2Sql but it was a waste of time because queries using left joins could not be tested - I fear the same problem is there with EF.Synagogue
setting up your data is quite easy - read upon Microsoft's suggestions for unit testing stored procedures. The same principal applies - you start a transaction, truncate the table, and insert what test data you need; then run the test and finally rollback the transaction. DB ends up in the state it started with and you get to manage your test data for each test.Gunlock
This seems to be the only way to fully test my application. Mocking IRepository will let you test the code that uses your data access code but not your actual data access code which is where 90% of my bugs are.Butcherbird
I
4

You are going to want to use a Mocking Framework to retrieve mock values rather than hitting the real data. Here are a list of a few mocking frameworks and links to some screencasts to help you get started:

Here are some screencasts on how to get started:

Infusionism answered 1/12, 2008 at 1:56 Comment(1)
You can't do this easily with the EF. Your answer is correct for interfaces or extendable POCOs.Theressathereto
S
4

I would like to share another input to this. I was able to test Entity Framework based components and application using TypeMock Isolator as well. However it is commercial.

Have a look at this post: Introducing Entity Framework Unit Testing with TypeMock Isolator

Salivation answered 14/9, 2009 at 23:29 Comment(0)
P
4

Due to the fact that version 1 of the Entity Framework breaks a few major software design principles, there really isn't any way to apply TDD when using it in your application. My research points to NHibernate if you're looking for an immediate solution. It was designed with unit testing in mind.

However, if you can wait, there appears to be hope for the next release of the Entity Framework: Test-Driven Development Walkthrough with the Entity Framework 4.0

Plebeian answered 26/1, 2010 at 4:30 Comment(0)
U
3

Although the examples might be very simplistic I have attempted to discuss a possible solution to this very issue. It involves separation of concerns and our dear friend Dependency Injection.

http://devblog.petrellyn.com/

Contact me if you want more details.

Uniparous answered 18/5, 2009 at 20:56 Comment(0)
H
2

I agree, a mocking framework is what you're after. You create "mocked" objects that aren't retrieved from your datasource, and you test the data in that object. I personally have been working with Moq, and I like it--there is also Rhinomocks, plus others.

Harrington answered 1/12, 2008 at 1:49 Comment(0)
V
2

After lots of frustration with this I finally have a solution that I'm happy with for at least part of the problem.

First use a repository interface something like:

public interface IRepository
{
    IQueryable<T> GetObjectSet<T>();
}

which we can use to return either an in memory collection or a real DB backed collection. Next encapsulate your queries into a query object with an interface that look something like this.

public interface IQuery<T>
{
    IQueryable<T> DoQuery(IQueryable<T> collection);
}

Now divide your unit tests into 2 groups. The first group will test that your queries are valid. do this like so:

[TestMethod]
public void TestQueryFoo()
{
     using(var repo = new SqlRepository("bogus connection string"))
     {
         var query = new FooQuery(); // implements IQuery<Foo>
         var result = query.DoQuery(repo.GetObjectSet<Foo>());  // as long as we don't enumerate the IQueryable EF won't notice that the connection string is bogus
         var sqlString = ((System.Data.Objects.ObjectQuery)query).ToTraceString(); // This will throw if the query can't be compiled to SQL
     }
}

The second set of unit tests can then freely test your business logic without worrying about the SQL compilation step which is, by far, where we run into the most trouble.

Its not perfect by any stretch of the imagination, triggers are obviously not going to be run, DB implemented constraints can be violated, and some issues with the context and database getting out of sync can crop up. So while end to end integration tests are still needed it is possible to catch what is IMO the most common issue to crop up at runtime in simple unit tests.

Vitals answered 7/6, 2013 at 18:38 Comment(1)
Can you please provide some sample codes using this approach? I also want to do unit test a web api 2 project which is using Entity FrameworkAnthropocentric
L
0

The BookLibrary sample application of the WPF Application Framework (WAF) project shows how an Entity Framework based application can be unit tested.

Lineup answered 28/7, 2010 at 16:57 Comment(0)
S
0

Here's an aggregation of the unit of work pattern+ in-memory database + t4 code generation to automatically generate a fake EF dbContext.

http://mockingcompetence.wordpress.com/2013/05/20/fakingefdatacontext/

there are some issues(invalid linq to EF queries and no FK enforcement) with exactly replicating a real EF db connection at this time.

However, having an in-memory context to quickly run unit tests is almost essential to being able to do TDD or any other kind of unit testing centric approach.

I will be posting updates to the above link as I figure out more of the issues.

Solute answered 30/5, 2013 at 10:37 Comment(0)
B
0

You could use in-memory data base for testing your Entity Framework model. Look here for more details

Bobo answered 15/10, 2013 at 12:3 Comment(0)
M
-1

How about using a mocking framework? It seems to me that a mocking framework can help you isolaye your business logic from the database.

Mayo answered 29/11, 2008 at 17:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.