Sneak Preview: Entity Framework 4.0 Testability Improvements

Published 18 May 09 04:56 PM | dpblogs 

Writing unit tests is a core practice in the vast majority of modern software development approaches. There are several benefits to it, but the one I personally tend to value the most is how I can take a component with enough unit test coverage and start refactoring it without worrying that I could accidentally introduce regressions.

With Test Driven Development and Unit Testing in general, it is critical that unit tests are lightning fast: in practice, you should run all tests for a component after applying each refactoring step, and that should not affect your rhythm. Whenever you feel the urge to skip the test runs, it is time to streamline your tests.

A well known way to accomplish this level of swiftness is to substitute the actual dependencies of the component being tested with test doubles. Test doubles expose the same API surface as the dependencies they impersonate, but instead of trying to emulate the often complex behavior of the real thing, they can limit themselves to provide canned responses or record the inputs received during the execution of the tests (which can help in verification even more).

When applied to the testing of the domain logic in an application using some O/RM technology, test doubles should ideally substitute the persistence layer. That way, unit tests typically never invoke the actual persistence framework, and more important, never in fact hit the database.

During the development Entity Framework 4.0, we spent a lot of time thinking how to make it easier to substitute Entity Framework in your unit tests. Here are a few improvements that we believe will make a difference on that front:

  1. POCO Support: As Faisal described in his post, you can now write your own entity classes that do not depend on Entity Framework, so you can instantiate them and use them more easily in your tests.
  2. Repository pattern: Repositories are the best known way to decouple the persistence layer from the rest of your application. While we won’t include or prescribe a particular variation of the pattern in the product, we have been working with Microsoft’s Patterns & Practices Team to produce new guidance and a Reference Implementation of this pattern (along with other patterns used Domain Driven Design) with Entity Framework. This exercise is helping us understand friction points and improvements we will hopefully address in this and future releases. Also, we will go deeper on this subject in a future blog post series.
  3. New IObjectSet<T> interface: the new ObjectSet<T> class derives from ObjectQuery<T> and represents a “root” query object for an EntitySet, that also has AddObject, DeleteObject and Attach methods. In order to improve testability, we also defined the corresponding IObjectSet<T> interface that derives from IQueryable<T>. IObjectSet<T> happens to be super easy to implement as an in-memory fake object. Provided that your queries and CUD operations can refer to instances of IObjectSet<T>, your code will now be easier and faster to test.
  4. Template-based code generation: No matter what pattern variations you prefer for Repository, UnitOfWork, persistence contexts, or their interfaces and corresponding test doubles, if you think you might end up writing the same boilerplate code once and again, you are probably better off customizing one of our T4 templates to suit your testability needs.
  5. LINQ to Entities Improvements: Some popular approaches to testability involve redirecting LINQ queries that at runtime would be executed against a database to be evaluated in-memory (using LINQ to Objects) during the execution of unit tests.  For those cases, the closer the behaviors of both LINQ implementations are, the lower the odds are that query bugs will go undetected until integration tests are executed. We have made several improvements in LINQ to Entities that we believe will help here:

a. Support for more LINQ operators, such as Contains, DefaultIfEmtpty, and improved support for Single/SingleOrDefault.

b. More translations for common Base Class Library patterns including various Math class methods, Guid.NewGuid, etc (some of this work is not included in Beta1).

c. Improved preservation of nested OrderBy operations.

d. Several bug fixes that further align the behavior of LINQ to Entities with LINQ to Objects.

The following sample code shows a very simple way to create and use a fake implementation of an ObjectContext that exposes properties of type IObjectSet<T>:

 

/// <summary>
/// Data access context interface for SimpleBlogging 
/// </summary>
public interface ISimpleBlogging : IDisposable
{
    IObjectSet<Blog> Blogs { get; }
    IObjectSet<Post> Posts { get; }
}


/// <summary>
/// Fake data access context for SimpleBlogging
/// </summary>
public class SimpleBloggingFakeContext : ISimpleBlogging
{
    private FakeObjectSet<Blog> _blogs;

    public IObjectSet<Blog> Blogs
    {
        get { return _blogs ?? (_blogs = new FakeObjectSet<Blog>()); }
    }

    private FakeObjectSet<Post> _posts;

    public IObjectSet<Post> Posts
    {
        get { return _posts ?? (_posts = new FakeObjectSet<Post>()); }
    }

    public void Dispose()
    {
    }
}

/// <summary>
/// Utility factory method for contexts
/// </summary>
private static ISimpleBlogging GetContext()
{
    ISimpleBlogging context = new SimpleBloggingFakeContext();
    InitializeWithCannedData(context);
    return context;
}
[TestMethod]
public void TestAddPost()
{
    using (ISimpleBlogging context = GetContext())
    {
        var blogging = new BloggingService(context);
        var newPost = blogging.AddPost(
            "Diego",
            "Hiatus", 
            "This is my last post for a while.");
        var blog = context.Blogs.Single(b => b.ID == "Diego");
        Assert.AreSame(newPost.Blog, blog);
    }
}

Stay tuned for a more in depth discussion of testability improvements, as well as other topics mentioned in this post.

Thanks,

Diego Vega
Program Manager, Entity Framework

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Sneak Preview: Entity Framework 4.0 Testability Improvements | ASP NET Hosting said on May 18, 2009 9:02 PM:

PingBack from http://asp-net-hosting.simplynetdev.com/sneak-preview-entity-framework-40-testability-improvements/

# Ryan Riley said on May 18, 2009 10:19 PM:

This looks terrific. Well done.

# progg.ru said on May 19, 2009 2:52 AM:

Thank you for submitting this cool story - Trackback from progg.ru

# DotNetShoutout said on May 19, 2009 4:14 AM:

Thank you for submitting this cool story - Trackback from DotNetShoutout

# Muhammad Mosa said on May 19, 2009 4:20 AM:

Ooooh, please hit me with more of those!

Good job guys! waiting for more.

# Muhammad Mosa said on May 19, 2009 4:21 AM:

Ah a question! can we use mocking?!

# Craig Stuntz said on May 19, 2009 9:10 AM:

This is good. I'm especially happy to see the increased support for LINQ and other methods in LINQ to Entities; this is the single biggest issue for me with regards to testability right now. I would love it if the Entity Framework would automatically generate a mocked ObjectContext. But any effort that you spend improving LINQ support is even more valuable to me.

# kesav kolla said on May 19, 2009 10:49 AM:

Does this version support all the new SQL Server 2008 data types?  Especially hierarchyid and geograpy types?

# Robert said on May 19, 2009 11:51 AM:

What about:

Being able to undo relationship changes easily? <-- huge

View Generation improvements (adding all those strings together)?

Underlying query method improvements?

Easier access to FK values?  I guess this might be solvable from a T4 perspective.

Is there a better disconnected tier story?

# DotNetBurner - ADO.NET said on May 19, 2009 7:59 PM:

DotNetBurner - burning hot .net content

# AlexJ said on May 20, 2009 2:27 AM:

@Kesav

Unfortunately no. With all the other things we've been doing we couldn't get to things like HierarchyId and Geography etc.

Alex

# Code Monkey Labs said on May 26, 2009 11:25 AM:

Pick of the week: IP and Non-Competes for Employees General Visual Studio 2010 Beta 1 : Go get the first beta of the next version of Visual Studio! Microsoft Set To Announce Commercial Availability of Windows Azure at PDC This Year : Alin Irimie has some

# VS2010学习 said on June 3, 2009 11:44 AM:

Introduction: From the moment I put my hands on Visual Studio.Net 2010 Beta 1 and I’m targeting EF4

# radyo dinle said on July 19, 2009 10:40 AM:

This is good. I'm especially happy to see the increased support for LINQ and other methods in LINQ to Entities; this is the single biggest issue for me with regards to testability right now. I would love it if the Entity Framework would automatically generate a mocked ObjectContext. But any effort that you spend improving LINQ support is even more valuable to me.

# Jason said on August 25, 2009 5:20 AM:

How to make data across the n-Tier application? For example, WCF?

# Jonas said on November 5, 2009 5:19 AM:

Why doesn't Microsoft do as they done with ASP.NET and JQuery. Microsoft don't know O/R-mappers and seems to focus more on drag'n drop funktionalities.

Why not begin to support Nhibernate instead?  

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required

Search

This Blog

Syndication

Page view tracker