Saturday, 28 August 2010

Unit Testing Entity Framework 4.0: A-Z in 3 Easy Steps

This article gives you an ultra-fast run down on how to start Unit Testing in Entity Framework 4.0 using C#; applying a suitable Code Generation Item to your Entity Data Model (EDMX) file, and building a Unit Test Project in Visual Studio 2010.

No external test harness is required, it doesn't rely on having a Repository pattern being implemented and you don't need to buy any new products. Just Visual Studio 2010 Professional Edition, Premium Edition or Ultimate Edition out of the box.

Terminology
The EDMX Code Generation Item used in this article generates two ObjectContext classes. When we refer to the Vanilla ObjectContext, this is the same strongly typed ObjectContext that is generated from your EDMX by default. The Mocking ObjectContext we refer to is another context used only for unit testing, which implements the same strongly typed interface, and is also generated from your EDMX file.

More details on the architecture of the artifact generator are provided here.


Step 1: Set Up the Code Generation Item

These steps will change your EDMX Code Generation Item to the ADO.NET Mocking Context Generator. This is what makes your C# code from your Entity Data Model (EDMX) file.
  • Open your EDMX file, right click the background, and from the context menu select Add Code Generation Item.
  • Select Online Templates->Database->ADO.NET Mocking Context Generator:


  • Open your EDMX file, right click the background, and from the context menu select Properties.
  • In the Properties change Code Generation Strategy to None. This will turn off the default Code Generation Item.



Step 2: Ensure "Context Agnostic" Code

Context Agnostic means that your Business Logic code shouldn't be aware of what context class it is using. We need to ensure that any hard dependencies on your generated Vanilla ObjectContext are replaced with references to your new generated ObjectContext Interface instead.

Identify Context "Gnostic" Code

We need to find anywhere in your Business Logic Layer that references the vanilla concrete ObjectContext:

class MovieLogic
{
    private MoviesContext _context;     // Hard dependency on vanilla ObjectContext

    public MovieLogic()
    {
        _context = new MoviesContext();     // Hard dependency on vanilla ObjectContext
    }
}

Option 1: Delegate responsibility to the client

To remove the hard dependency, the simplest option is to ensure all ObjectContext references use the ObjectContext Interface instead, and take on the ObjectContext instance in their constructor:
class MovieLogic
{
    private IMoviesContext _context;    // Interface used instead: context agnostic

    public MovieLogic( IMoviesContext context )
    {
        _context = context;     // Instantiation responsibility is delegated to caller
    }
}
The Business Logic Client can then be re-engineered to instantiate a vanilla ObjectContext object for us when the Business Logic object is instantiated:
MovieLogic logic = new MovieLogic( new MoviesContext() );
Note
Your application will never instantiate a Mocking Context, as this is only used when testing your business logic in your Unit Test Project.



Option 2: Delegate responsibility to a factory

If your Business Logic objects are instantiated all over the place, then it might be easier to contain the instantiation responsibility within a factory, and call the factory when a context is needed from the Business Logic objects themselves:
class MovieLogic
{
    private IMoviesContext _context;

    public MovieLogic()
    {
        _context = MyContextFactory.CreateContext();    
            // Instantiation responsibility is delegated to factory
    }
}
Implementing the Factory
Whilst no implementation of an example factory is given here, the factory just needs to return a new instance of your Vanilla ObjectContext, unless the "testing" flag is raised, when a Mocking ObjectContext will be instantiated instead.



Step 3: Create the Unit Tests

To create the unit tests in Visual Studio, a new test project needs to be created. This project will contain the Unit Test class that runs all the tests, and the code required to set up the mocking context, mock data, and the calls to the business logic.
  • Right click your solution, and select Add -> New Project
  • From the Add New Project Dialog select Visual C# -> Test -> Test Project:


  • Add a Reference in your new test project to your Business Logic Project.
  • Add a Reference to System.Data
  • Add a Reference to System.Data.Entity

Set up the test "database"

This step creates a fresh mocking context before every test is executed. The mocking context is populated with some sample data that the tests can use. Additionally any test can set up its own data as part of its testing.
  • In your new test project, open your Unit Test code file (eg. "UnitTest1.cs")
  • Add a member (eg. _context) to your unit test class, of the type of your ObjectContext Interface. The name of the interface will be shown if you expand the *.Context.tt file in the project containing your EDMX file:

  • private IMoviesContext _context;
  • Add a new function with the TestInitialize attribute. This will cause your function to be executed before every test. Create a mock context and fill it with your mock data. The name of the mocking context class will be shown if you expand the *.Context.tt file in the project containing your EDMX file:

  • [TestInitialize]
    public void TestInitialize() 
    { 
        _context = new MoviesContextMock();
    
        Actor[] actors = new Actor[]
        {
            new Actor() { Id = 1, Name = "Robert De Niro" },
            new Actor() { Id = 2, Name = "Ray Liotta" },
            new Actor() { Id = 3, Name = "Joe Pesci" },
            new Actor() { Id = 4, Name = "Jodie Foster" }
        };
    
        Movie[] movies = new Movie[]
        {
            new Movie() { Id = 1, Title = "Goodfellas",  ReleaseYear = 1990, Rating=5 },
            new Movie() { Id = 2, Title = "Taxi Driver", ReleaseYear = 1976, Rating=5 },
        };
    
        movies[ 0 ].Cast.Add( actors[ 0 ] );
        movies[ 0 ].Cast.Add( actors[ 1 ] );
        movies[ 0 ].Cast.Add( actors[ 2 ] );
        movies[ 1 ].Cast.Add( actors[ 0 ] );
        movies[ 1 ].Cast.Add( actors[ 3 ] );
    
        actors.ToList().ForEach( actor => _context.Actors.AddObject( actor ) );
        movies.ToList().ForEach( movie => _context.Movies.AddObject( movie ) );
    }


Implement Test Methods

Create some functions on your new unit test class, with the attribute TestMethod. These will execute the individual unit tests for your business logic.

Use the Assert.* methods to check the results of calls to your business logic. These calls will be evaluated by the test engine.

[TestMethod]
public void TestGetMovieByTitle()
{
    MovieLogic logic = new MovieLogic( _context );
    Movie movie = logic.GetMovieByTitle( "Goodfellas" );
    Assert.AreEqual( 1, movie.Id );
}

[TestMethod]
public void TestGetMovieByTitleBad()
{
    MovieLogic logic = new MovieLogic( _context );
    Movie movie = logic.GetMovieByTitle( "Arial the Little Mermaid" );
    Assert.AreEqual( null, movie );
}

[TestMethod]
public void TestGetMovieByReleaseYear()
{
    MovieLogic logic = new MovieLogic( _context );
    Movie[] movies = logic.GetMovieByReleaseYear( 1976 );
    Assert.AreEqual( 1, movies.Length );
    Assert.AreEqual( "Taxi Driver", movies[ 0 ].Title );
}



Running the Tests

To run the tests, select Test -> Run -> All Tests In Solution.
The Test Results panel will pop up, and give you the results of your tests:



Frequently Asked Questions

Where's my Vanilla ObjectContext's AddToObjectSetName method gone?

This method has now been deprecated in Entity Framework 4.0. Instead of using AddToObjectSetName, use <My Vanilla ObjectContext>.<ObjectSetName>.AddObject().

How do I unit test my EDMX EntityObject Functions?

Functions map to Stored Procedures in your database. You cannot, therefore, unit test your C# code and expect to call an SP as part of the unit test. You'll have to make sure that the high level logic function that calls the stored procedure is not included in your code C# tests; if you can break the function down into smaller method units within the logic class you may still be able to test the smaller logic units that don't require the SP. For unit testing the SP however, you need to create a Database Unit Test project.

How do I perform a unit test that includes database connectivity?

This, semantically speaking, is not possible. A code Unit Test should be testing units of code. If you need to perform a test across your code into a persistent storage medium, then this is an Integration Test. The Unit Testing phase is performed before the Integration Testing phase.

Thursday, 19 August 2010

Maintenance-Free Mocking for Unit Testing with Entity Framework 4.0

If you are trying to unit test in Entity Framework 4.0, you may have come across an apparent lack of architectural support for unit testing integration. Visual Studio 2010 appears to have excellent support for integrating Unit Test Projects into your solution, but no out-of-the box integration for using an Entity Framework Data Model (EDMX) generated Object Context is provided.

This article discusses how to implement a Mocking based approach to Unit Testing in a way that requires zero future code maintenance; generated automatically from the EDMX. The implementation doesn't require anything more than Visual Studio 2010. The finished product is implemented as a self-contained Visual Studio 2010 Item Template, available for download (see bottom of article).

Unit Testing & Mocking: A Brief Synopsis

If you want to unit test a Business Logic Layer, the BLL mustn't access the database within any part of the test cycle. If this happens the tests could be "contaminated" with errors from other layers. Additionally this sort of approach, whilst valid for full system testing, increases the overhead of performing the tests; a test database has to be set up, the schema implemented and the data put into a known state. A unit test only deals with testing on the component level, and shouldn't be dependent on persistent data, nor should it persist data itself.

Mocking is the process of swapping a functional object with a simulated mock object which shares the same interface. In the context of a BLL, this is normally the DAL "facade" or manager class; like your specialised ObjectContext class in Entity Framework. This mock object may then be provided to the test client in the stead of the functional class, and instead of retrieving and persisting data to the database, the mock object will gather data and/or report for testing purposes.

The Problem

The issue with attempting to "drop in" a mocking approach in Entity Framework is that your specialised ObjectContext class, the facade class generated from the EDMX, has no generated interface containing the specialised functionality. Without an interface, it's impossible to implement the classical approach to implementing a Mock ObjectContext:

From the class diagram shown you can see that MyObjectContext derives directly from ObjectContext; the only way to provide a Mock ObjectContext using the out-of-the-box architecture would be either a reflection or proxy-based approach, or by completely overriding the functionality in the base class (creating a refused bequest smell). All undesirable as they are complicated, potentially more error prone, and more difficult for a new developer on the team to pick up as they don't follow the classical Mocking approach.




The Solution

The solution is very simple, thanks to the new T4 (Text Template Transformation Toolkit) integration provided in Entity Data Modeller in Entity Framework 4.0. For the uninitiated, T4 is what is already used to generate your specialised ObjectContext and EntityObject classes from your EDMX file behind the scenes.

By using T4 we can instead come up with the following generated architecture, with very few changes to the out-of-the-box solution:

Note that MyObjectContext now implements IMyObjectContext. This allows the implementation of the MockMyObjectContext, and for it to share the same interface. This interface is passed to business logic clients instead of the concrete contexts, so that they are unaware if they are talking to the database, or instead being unit tested.

Download and Instructions

The download link and (very simple) guide to using is available here.


Thoughts and Considerations

Change Tracking and EntityObject
You may have noticed that the strongly typed entity object now derives from Object instead of EntityObject. This is because the entity object is now implemented as a POCO object as the complex change tracking interferes with the mocking. However, Entity Framework 4.0 employs generated proxy classes to manage change tracking if POCO objects' properties are implemented as virtual. See POCO in the Entity Framework.

ObjectQuery<T> Include
In the mocking context, ObjectSet<T> can no longer be used as this is a concrete object that liaises with the database. The context interface instead generates collections of type IObjectSet<T>, and both the concrete functional context and the mocking context implement this.

However, because ObjectSet<T> derives from ObjectQuery<T> this means we lose Include. To provide a workaround, the T4 generator implements an extension class for the interface IQueryable, that provides an Include method. This should mean that you can continue to use your existing code without any changes.

The workaround used was taken from Julie Lerman's Blog.

Wednesday, 18 August 2010

ADO.NET Mocking Context Generator: Visual Studio 2010 Template

In my previous article, I discussed how to put together a Visual Studio 2010 Template to provide Maintenance-free Mocking for Unit Testing in Entity Framework 4.0.

The template is available for download from Microsoft, here.

You can also download it using Visual Studio 2010, by selecting Online Templates from the Add New Item dialog.

How to Use

Just like any other Entity Framework Artifact Generator, after installing:
  • Open your Entity Framework Model (EDMX) file
  • Right click the background and press Properties
  • Set Code Generation Strategy to None.
  • Right click the background again, and select Add Code Generation Item
  • From the Add New Item dialog, select ADO.NET Mocking Context Generator

    At some point I might extend this page to include a brief guide to unit testing. Until then, Julie Lerman's Blog is a good resource, along with the ADO.NET Team Blog.



  • Monday, 9 August 2010

    Stateless paging in SQL Server CE 3.51 using Entity Framework

    If you are bound to Microsoft SQL Server Compact Edition 3.51 (or indeed, I think any of 3.x) using Entity Framework then you may have found the lack of support for server-stateless paging through queries:
    SELECT VALUE employee 
    FROM Employees
    ORDER BY employee.Name 
    SKIP(@skip) LIMIT (@limit)
    
    Both the LINQ Skip() and Take() extensions, along with the Entity SQL commands SKIP and LIMIT commands all come back with runtime errors.

    Paging with TOP

    This is an alternative SQL keyword that can be employed in SQL Server 3.51 CE. Normally it provides a function similar to LIMIT, although has no equivalent to SKIP, which makes it pretty useless. However, with a bit of fudging, it's possible to come up with an Entity SQL query that does the same thing:

    SELECT VALUE skip_query FROM
    (
        SELECT VALUE TOP (@count) take_query 
        FROM 
        (
            SELECT VALUE TOP(@end) employee
            FROM Company.Employees AS employee
            ORDER BY employee.Name ASC, employee.Id ASC
        ) 
        AS take_query
        ORDER BY take_query.Name DESC, employee.Id DESC
    ) 
    AS skip_query
    ORDER BY skip_query.Name ASC, employee.Id ASC;
    

    Considerations

    Admittedly, we've got the parameters count and end to use, so it's not exactly the same as SKIP and LIMIT, but it works just as well.

    If you're worried about efficiency, the improvements of properly paging should vastly overcome the use of nested statements and their performance impact on CE.

    Also, if you look at the documentation for TOP it does give a warning that it's non-deterministic. However note that as long as an ORDER BY clause is specified, this is negated. Do however note that each record must have a unique placement in the ORDER BY clause. I highly recommend putting the primary key as a secondary ordered field to ensure deterministicity, as shown in the example above.



    Source Code

    There's more than one way to implement an Entity SQL Query, but if you want implicit object materialisation, then using an ObjectQuery instance is the easiest way.

    private const string SkipLimitQuery = "SELECT VALUE skip_query...";
    private Employee[] GetEmployeesPaged( int start, int count )
    {
        using ( Company context = new Company() )
        {        
            ObjectQuery<DAL.Rom> query = context.CreateQuery<Employee>( SkipLimitQuery );
            command.Parameters.Add( new ObjectParameter( "count", count ) );
            command.Parameters.Add( new ObjectParameter( "end", start + count ) );
    
            return query.ToArray();
        }
    }