Category Archives: Data Access

Agile Entity Framework 4 Repository: Part 6: Mocks & Unit Tests

I did finish this series, honest I did. But not in the blog. I’ve shown this in a number of conferences and even in my book, but I never came back and wrote it all down. In fact, I had the whole solutino written before I began the series, but it has gone through a lot of changes.

Where did I leave off?

  1. Agile Entity Framework 4 Repository: Part 1- Model and POCO Classes
  2. Agile Entity Framework 4 Repository: Part 2- The Repository
  3. Agile EF4 Repository: Part 3 -Fine Tuning the Repository
  4. Agile EF4 Repository: Part 4: Compiled LINQ Queries
  5. Agile Entity Framework 4 Repository Part 5: IObjectSet and Include
  6. Agile Entity Framework 4 Repository: Part 6: Mocks & Unit Tests

So finally, I can create the mocks and the tests.

I’m not going to walk through this in great detail since I’ve already done that in my book and don’t feel like laying the whole thing out again. And because my solution has evolved, this last bit of code might not line up exactly with the prior blog posts. You’ll find

I have a single project for tests. It has references to the model classes, the Repositories, the interfaces (IContext, IObjectSet and IEntityRepository), the model and ObjectContext (for integration tests) and System.Data.Entity.

In order to run unit tests, I have a mock context that implements IContext. My real “hit the database” context, also implements IContext. But the mock contexts will return data by creating some fake data on the fly. Yes I said contexts with the “s” on the end. I have more than one.

Because this is all dependent on using IObjectSet (previous post) rather than the ObjectSet, and you can’t instantiate an interface, you’ll need another implementation of the IObjectSet which you can use in your fake context.

It’s pretty simple. The key is to implement all of the interfaces that IObjectSet implements as well and the logic of those methods is fairly common. The trick is to replace the specific methods of the ObjectSet (e.g. Attach, DeleteObject, etc) with generic List methods. So Attach will become Add, DeleteObject will become Remove, etc.

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Data.Objects;

namespace POCOEFTests
{
  class MockObjectSet<T>: IObjectSet<T> where T : class
  {
    readonly IList<T> _container=new List<T>();

      public void AddObject(T entity)
    {
      _container.Add(entity);
    }

    public void Attach(T entity)
    {
      _container.Add(entity);
    }

    public void DeleteObject(T entity)
    {
      _container.Remove(entity);
    }

    public void Detach(T entity)
    {
      _container.Remove(entity);
    }

    public IEnumerator<T> GetEnumerator()
    {
      return _container.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
      return _container.GetEnumerator();
    }

    public Type ElementType
    {
      get{return typeof(T);}
    }

    public System.Linq.Expressions.Expression Expression
    {
      get { return _container.AsQueryable<T>().Expression; }
    }

    public IQueryProvider Provider
    {
      get { return _container.AsQueryable<T>().Provider; }
    }
  }
}

The IContext interface requires that any implementor return the same set of IObjectSets (Contact, Customers, etc). Our real context already does this (again, by hitting the database). You’ll see that the IObjectSet properties in the mock call local methods which create fake data on the fly to populate the ObjectSet. The various sets of data are related to each other through their foreign keys.

using System;
using System.Collections.Generic;
using System.Linq;
using BAGA;
using BAGA.Repository.Interfaces;
using System.Data.Objects;

namespace POCOEFTests
{
  class MockContext : IContext
  {

    private IObjectSet<Reservation> _reservations;
    private IObjectSet<Customer> _customers;
    private IObjectSet<Trip> _trips;
    private IObjectSet<Payment> _payments;
    private IObjectSet<Contact> _contacts;

    #region IContext Members

    public IObjectSet<Contact> Contacts
    {

      get
      {
        CreateCustomers();
        return _contacts;
      }

    }

    public IQueryable<Customer> Customers
    {
      get
      {
        CreateCustomers();
        return _customers;
      }
    }

    public IObjectSet<Trip> Trips
    {
      get
      {
        CreateTrips();
        return _trips;
      }
    }

    public IObjectSet<Reservation> Reservations
    {
      get {
        CreateReservations();
        return _reservations;
      }
    }



    public IObjectSet<Payment> Payments
    {
      get
      {
        CreatePayments();
        return _payments;

      }
    }

    public string Save()
    {
      throw new NotImplementedException();
    }

public IEnumerable<T> ManagedEntities<T>()
{
  if (typeof(T) == typeof(Reservation))
  {
    var newRes = new Reservation
                   {
                     ReservationID = 1,
                     ContactID = 20,
                     TripID = 1,
                     ReservationDate = new DateTime(2009, 08, 01)
                   };

    var managedRes = new List<Reservation>{newRes};
    return (IEnumerable<T>) managedRes.AsEnumerable();
  }
  return null;
}
    
  
    public bool PreSavingValidate(out string validationErrors)
    {
      bool isvalid = true;
      validationErrors = "";

      foreach (var res in ManagedEntities<Reservation>())
      {
        string validationError;
        bool isResValid = res.ValidateBeforeSave(out validationError);
        if (!isResValid)
        {
          isvalid = false;
          validationErrors += validationError;
        }
      }

      return isvalid;
    }

    #endregion

    private void CreateReservations()
    {
      if (_reservations == null)
      {
        _reservations = new MockObjectSet<Reservation>();
        //one customer has two reservations, the other only has one
        _reservations.AddObject(new Reservation { ReservationID = 1, TripID = 1, ContactID = 19 });
        _reservations.AddObject(new Reservation { ReservationID = 2, TripID = 2, ContactID = 19 });
        _reservations.AddObject(new Reservation { ReservationID = 3, TripID = 1, ContactID = 23 });
      }
    }
    private void CreateCustomers()
    {
      if (_customers == null)
      {
        _customers = new MockObjectSet<Customer>();
        _customers.AddObject(new Customer { ContactID = 1, FirstName = "Matthieu", LastName = "Mezil" });
        _customers.AddObject(new Customer { ContactID = 19, FirstName = "Kristofer", LastName = "Anderson" });
        _customers.AddObject(new Customer { ContactID = 23, FirstName = "Bobby", LastName = "Johnson" });
      }
    }

    private void CreateContacts()
    {
      if (_contacts==null)
      {
        _contacts = new MockObjectSet<Contact>();
        _contacts.AddObject(new Customer { ContactID = 1, FirstName = "Matthieu", LastName = "Mezil" });
        _contacts.AddObject(new Customer { ContactID = 19, FirstName = "Kristofer", LastName = "Anderson" });
        _contacts.AddObject(new Customer { ContactID = 23, FirstName = "Bobby", LastName = "Johnson" });
      }
    }
    private void CreatePayments()
    {
      if (_payments == null)
      {
        _payments = new MockObjectSet<Payment>();
        //create (not enough) payments for reservation 1 (a $1000 trip)
        _payments.AddObject(new Payment
        {
          PaymentID = 1,
          ReservationID = 1,
          Amount = 500
        });
        //create a full payment for reservation 2
        _payments.AddObject(new Payment
        {
          PaymentID = 2,
          ReservationID = 2,
          Amount = 1200
        });
      }
    }
    private void CreateTrips()
    {
      if (_trips == null)
      {
        _trips = new MockObjectSet<Trip>();
        //one customer has two reservations, the other only has one
        _trips.AddObject(new Trip { TripID = 1, DestinationID = 1, TripCostUSD = 1000 });
        _trips.AddObject(new Trip { TripID = 2, DestinationID = 2, TripCostUSD = 1200 });
      }
    }

  }
}

 

This mock context creates valid data. I also have some other mock contexts that intentionally create data that is bad. I can use those contexts to test that my validation code properly responds to bad data.

Here’s an example of two tests that use two different mock contexts. They test the PreSavingValidate method that I created in an earlier post in this series. Because that method is part of the context, I literally copied it from the “real” context into the mock context so that I can test the same exact code.

    [TestMethod()]
    public void PreSavingValidationsGOODTest()
    {
      IContext context = new MockContext();
      bool valid;
      string validationErrors = "";
      valid = context.PreSavingValidate(out validationErrors);
      Assert.IsTrue(valid);
      Assert.AreEqual(validationErrors, "");
    }

    [TestMethod()]
    public void PreSavingValidationsBADDATATest()
    {
      IContext context = new MockContextBadData();
      bool valid;
      string validationErrors = "";
      valid = context.PreSavingValidate(out validationErrors);
      Assert.IsFalse(valid);
      Assert.AreNotEqual(validationErrors, "");
    }

Here’s a test that tests the GetReservationsForCustomer method in the Reservation repository. That is a method that first validates the incoming ID and then if it’s good executes the query. This method is a really good example of why you want to mock. I can’t separate the ID validation from the query execution so I need  a way to “fake” the query execution when I test the ID validation. I’m instantiating the mock and passing it into the ReservationRepository u sing an overload of the constructor. IF I did not pass in a context, the repository will instantiate a new BAEntities, which is the context implementation that executes the real queries against the database.

[TestMethod()]
public void GetReservationsForCustomerValidId()
{
  var context = new MockContext();
  var target = new ReservationRepository(context);
  int customerId = 20; //valid id
  IList<Reservation> actual = target.GetReservationsForCustomer(customerId);
  Assert.IsNotNull(actual);
}

There are a lot of other tests I ran through as well.

Now that I have posted how to build this whole thing, I know everyone will just ask me to post the code so they can just use it rather than READING the blog posts I made such an effort to write. I’ll have to find the time to clean it up (it’s a big sample from my book) before I post it but I REALLY need to get the BOOK FINISHED! (I Know you want me to). So in the mean time, everything you need is in this series. And the rough draft of the relevant chapter is online as part of the Rough Cuts publication of the 2nd edition of my book. One BIG difference from this series and the solution in my book is that I’ve also implemented a unit of work in the book. Therefore I have tests and production code where follow this pattern instead:

[TestMethod()]
public void GetReservationsForCustomerValidIdUnitOfWork()
{
  var context = new MockContext();
    var uow = new UnitOfWork(context);
  var target = new ReservationRepository(uow);
  int customerId = 20; //valid id
  IList<Reservation> actual = target.GetReservationsForCustomer(customerId);
  Assert.IsNotNull(actual);
}

Enjoy!

RIA Services and Entity Framework POCOs

WCF RIA Services contains a special domain service for entity framework which will automatically be used if you use the Domain Service template in Visual Studio.

This winter I tried the template with a few projects. One of them had EntityObjects and the other had POCO entities.

The EntityObjects worked great, but the POCO entities didn’t work at all.

The bulk of the problems were based on the fact that the EntityDomainService used methods from the first version of Entity Framework that relied on EntityObject being passed in.

I showed this to some of the RIA Services team and how using ObjectSet methods and other .NET 4 methods would easily fix this so that the EntityDomainServive would work with EntityObjects and POCO entities which do not inherit from EntityObject.

The new RIA Services bits released at MIX reflected most of these changes to the EntityDomainService template. Here’s a domain service generated from a POCO entity.

 [EnableClientAccess()]
  public class DomainService1 : LinqToEntitiesDomainService<AdventureWorksSuperLTEntities>
  {
    public IQueryable<Customer> GetCustomers()
    {
      return this.ObjectContext.Customers;
    }

    public void InsertCustomer(Customer customer)
    {
      if ((customer.EntityState != EntityState.Detached))
      {
        this.ObjectContext.ObjectStateManager.ChangeObjectState(customer, EntityState.Added);
      }
      else
      {
        this.ObjectContext.Customers.AddObject(customer);
      }
    }

    public void UpdateCustomer(Customer currentCustomer)
    {
      this.ObjectContext.Customers.AttachAsModified(currentCustomer, this.ChangeSet.GetOriginal(currentCustomer));
    }

    public void DeleteCustomer(Customer customer)
    {
      if ((customer.EntityState == EntityState.Detached))
      {
        this.ObjectContext.Customers.Attach(customer);
      }
      this.ObjectContext.Customers.DeleteObject(customer);
    }
  }

But there is still one more tweak you need to make.

Notice that the EntityState property is used in the Insert and Delete methods. EntityState is exposed by EntityObject so classes that inherit from EntityObject will have an EntityState property. POCO classes, however don’t have an EntityState property. Even if they did, these methods rely on the EntityState value that the ObjectContext supplies, which is what EntityObject.EntityState provides.

So this template still won’t work with POCOs.

Here’s how you can fix that.

Introduce a method into the class that knows how to read the EntityState from the context.

   private EntityState GetEntityState(object entity)
    {
      System.Data.Objects.ObjectStateEntry ose;
      if (this.ObjectContext.ObjectStateManager.TryGetObjectStateEntry(entity, out ose))
        return ose.State;
      else
        return EntityState.Detached;
    }

Then replace code which needs EntityObject.EntityState with a call to this method.

In the above example, it is two calls to customer.EntityState which need to be replaced.

 OLD: if ((customer.EntityState == EntityState.Detached)) 
 NEW: if ((GetEntityState(customer) != EntityState.Detached))

This RIA Services bug from MIX bits has been fixed but until new bits are released, watch out!

The MIX build of RIA services has a bug that has been fixed since. But you might experience it as I did this morning and go around in circles for a while. This blog post is to help you avoid wasting that time.

I normally create my model is in its own project and hadn’t seen this problem until this morning.

If you add a model into a RIA Services project (e.g., the web project created from the Silverlight Business Application template), you must build the project before you create a new Domain Service Class with the wizard.

If the project wasn’t built in advance, then you will see the model, but not the entities:

dsnoentities

What I did then was Cancel and build the project. But it was too late. The entities would not show up after this when I tried to create a new Domain Service class. The only way to get them to show at this point is to close and reopen Visual Studio.

It’s a bug and has been fixed post-Mix, but until then, remember to build after you add in the model file.

Hopefully you won’t spend as much time as I did trying to understand the problem. Thanks to Jeff Handley and Ron Cain from the RIA Services team who finally identified the problem and confirmed that it’s been eradicated.

Include Method Extension for IObjectSet – What about the mocks?

Eager loading with Entity Framework depends on the special ObjectQuery.Include method. We’ve had that from Day 1 (first version of ef).

Now we use ObjectSets in EF4 which inherit from ObjectQuery (thereby inheriting Include) and also implement IObjectSet.

IObjectSet allows us to break the queries apart from ObjectQuery and ObjectContext so we can write persistent ignorant, testable code.

But IObjectSet doesn’t come with the Include method and you have to create an extension method to continue using it.

This is not new. Lots of people have blogged about it before including myself. Here’s a post I wrote about using Include with IObjectSets: http://thedatafarm.wpengine.com/blog/data-access/agile-entity-framework-4-repository-part-5-iobjectset/

This extension method works great when the IObjectSet is the one for your true EF query, therefore an ObjectSet which inherits from ObjectQuery and can leverage the Include.

But what happens when you are testing a method that contains an eager loaded query with Include and you are using a mock context, not the real EF ObjectContext?

The Include method will get ignored.

For example, you may have a method such as:

 

public List<Customer> GetCustomerWithOrders(int customerId)
{
   return context.Customer.Include(“Orders”)
.Where(c=>c.Id==customerId).ToList(); }

In *real* EF, “context.Customer” is an ObjectSet, but if you are using a mock context, then it’s an IObjectSet with no Include.

All you’ll get back after running through the extension method is the Customer — with no orders. But at least the method won’t crash and burn.

But what if the method does something like this:

public string BuildEmailForCustomerWithOrders(int customerId)
{
   var cust=  context.Customer.Include(“Orders”).FirstOrDefault(c=>c.Id==customerId);
   if (cust.Orders>0)
    return “Dear” + cust.Name + “, Thanks for your order”
   else
    return “Dear” +cust.Name+ “, Screw you for not placing any orders”;
}

You might then have a test to be sure that good customers get a nice email and bad customers get the nasty email.

With the mocks, you can’t test that because Orders will always be 0.

Here’s an easy solution….just create a special mock context that is used anywhere you need to test methods that contain Includes.

And instead of it’s Customers property returning customers, the Customers property should construct a customer with some orders in its Orders property and return that.

Long story to get to a very simple solution – which may be obvious to pro testers – but is not necessarily to us newbies.

I already have a bunch of mocks…good data mocks to test valid validations…bad data mocks to test invalid validations, etc. So creating a mock so that my methods that happen to contain Include queries can still be tested was a no-brainer (once I was confident there was no way (and really, no need) to generically emulate the Include behavior).

Entity Framework POCO Template for .NET 3.5

UPON REFLECTION, I DECIDED THAT THIS POST WAS PRETTY MISGUIDED (must have been one of those days…).

So, for safety , I have removed it completely.

You *can* use T4 to customize the code generated for EntityObjects but if you begin with the T4 EntityObject template and replace .NET 4.0 specific logic with old style. FOr example ObjectSet & CreateObjectSet needs to be replaced by ObjectQuery and CreateQuery.

When I have some time, I will update this post to show how to do it.

Two more Entity Framework videos on Pluralsight

Two new videos that I have created for Visual Studio 2010 have just been published to Pluralsight On-Demand.

If you don’t have a Pluralsight subscription (yet), these videos are available as part of POD’s free guest pass along with lots of other great content.

The new vids are “Exploring the Classes Generated from an Entity Data Model” and “Consuming an Entity Data Model from a Separate .NET Project”.

EFPSOD

They’ll be available on the MSDN Data Developer center as well (msdn.microsoft.com/data) in the very near future.

If timestamp is deprecated, why do none of the current db tools support rowversion?

Perhaps the title of this blog post will suffice, but I just wanted to highlight this problem.

If you were to look up the timestamp data type in the SQL Server 2008 documentation, this is waht you will find within the topic article:

“The timestamp syntax is deprecated. This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature.”

It’s been there for quite some time.

The functionality of rowversion and timestamp are the same. It’s just a name change to align with the rest of the world and end the confusion caused by the word “time” in the name.

So let’s say you are good at following these types of recommendations and as you create a new table in SQL Server Managmenet studio, you attempt to use rowversion rather than timestamp.

Here’s what you’ll see:

norowversion

rowversion is not an option.

It’s also not an option if you try to use the column’s properties window.

You can use TSQL to create the column:

ALTER TABLE dbo.Address ADD RowVersion rowversion

But the designer will still display it as a timestamp. The object explorer also says its a timestamp.

norowversion2

What about Visual Studio 2010?

The server explorer doesn’t grok rowversion either and shows the field as a timestamp.

And finally, the tool I use frequently, the Entity Data Model designer also does not recognize rowversion.

If I create an entity from this table, the store schema’s representation of the field is:

<Property Name="RowVersion" Type="timestamp" Nullable="false" StoreGeneratedPattern="Computed" />

I can change this manually and it is valid within the schema.

I’m confused. Microsoft wants us to use rowversion but they sure don’t make it easy!

Again, timestamp and rowversion do exactly the same thing. This is only a “decorative” change.

Yet, I care a lot about this because I use timestamp fields in the sample database for my book, Programming Entity Framework. The term “timestamp” shows up in many screenshots and I discuss it frequently throughout the book. I am considering taking on the task of changing every visual and textual reference to rowversion to be in line with Microsoft’s recommendations. Bt if it’s not easy for users to use the rowversion type, I’m very hesitant to force it on them.

Crystal Reports and Visual Studio 2010

If like me, you have a “can’t live with it, can’t live without it” relationship with Crystal Reports and have made a significant investment in reporting with their tools, you might be digging around the VS2010 RC looking for Crystal.

CR has been embedded into Visual Basic and Visual Studio for many versions. My experience goes back as far as Visual Basic 4, but in fact it started in 1993 with VB 2!

But it’s not in VS2010 RC. Well, kinda not in there.

Crystal Report is included in the project item templates:

cra

But when you select it, something odd happens. Rather than a designer, you will get this window:

crb

So it’s still available as a free extension to VS, just not built in. It’s odd that Crystal isn’t listed in the Extensions gallery that you can access through the VS2010 Extension Manager (on the Tools menu) or online at www.visualstudiogallery.com.

There’s an extensive blog post on the SAP website about Crystal Reports for Visual Studio 2010 which also lists new features, including a WPF report viewer.

I haven’t tried any of them out yet. What I’m most interested in is the design time experience with Entity Framework graphs. In VS2008, neither CR nor MS Reports recognizes navigation properties. A quick look at MS Reports (rdlc) in VS2010 suggests that this hasn’t changed. I’ll have to dig further at some point.