I had few previous posts about DDD & TDD with Entity Framework that you might need to return to them before you proceed with this post. To summarize these posts, I was trying to build testable Models that is based on EF. But EF doesn't support Persistence Ignorance in its first version which make testing it in most cases require a database connection where you can test you code against it. My target was to build a testable models based on EF and that is independent of any underlying data source.
Introduction, Domain Model Review:

The above image shows class diagram of my northwind domain model. It is a set of interfaces where I define data contracts of each entity. It is very simple, but there is one thing I want to highlight in this model. It is the IEntityCollection generic interface. Actually this is an empty interface that is considered a combination of ICollection<T>, IEnumerable<T>, IEnumerable and IListSource. This interface defines a collection of related entities such as the case ICategory that should contains a collection of IProduct.
So ICategory should contain an IEntityCollection of products IEntityCollection<IProduct>. Same thing for ISupplier. And for IProduct it should contain a navigation property for both ISupplier and ICategory.
Issue with EF generated entities:
EF generated entities cannot be tested without physical connection to data source. For example generated entities cannot be mocked because it will require a physical data source. But interfaces can be mocked. And because we have entities that implements those interfaces, then we need to test these entities.
Regardless of mocking, you'll also face troubles when you work with real entities specially when you try to access navigation properties or collections. Especially if the collection are lazy loading ones. Then you will need to call Load which will require to hit the data store to retrieve related collection of data.
What Exactly I need to test in entities?
Basically I need to test navigation properties both scalar and collection ones. Navigation properties in EF depends on EntityReference<T> and EntityCollection<T> classes. Both are sealed classes, also these generated properties such as EntityCollection of products will require to hit data store. So I cannot mocke instance of those classes.
For example I need to test Category.Products that it loads data if not already loaded. This is what I want to test and without connecting to data store. Same thing for Product.Category which will require the EntityReference<Category> to be loaded in order to Category property of Product class to return a result.
So I will need to mock EntityReference<T> properties and EntityCollection<T> properties. And as I mentioned above they cannot be mocked because they are sealed. So my solution was to build a wrapper for both classes in order to be able to mock them.
public class EntityReferenceWrapper<TEntity>
where TEntity : class, IEntityWithRelationships, IEntity
{
EntityReference<TEntity> _entityReference;
public EntityReferenceWrapper(EntityReference<TEntity> entityReference)
{
_entityReference = entityReference;
}
[SoapIgnore]
[XmlIgnore]
public virtual TEntity Value
{
get { return _entityReference.Value; }
set { _entityReference.Value = value; }
}
public void Attach(TEntity entity)
{
_entityReference.Attach(entity);
}
public ObjectQuery<TEntity> CreateSourceQuery()
{
return _entityReference.CreateSourceQuery();
}
public virtual void Load()
{
_entityReference.Load();
}
public virtual bool IsLoaded
{
get
{
return _entityReference.IsLoaded;
}
}
}
public class EntityCollectionWrapper<TInterface, TEntity> : IEntityCollection<TInterface>
where TInterface : class, IEntity
where TEntity : class, IEntityWithRelationships, TInterface
{
private readonly EntityCollection<TEntity> _entityCollection;
public EntityCollectionWrapper(EntityCollection<TEntity> entityCollection)
{
_entityCollection = entityCollection;
}
public int Count { get { return _entityCollection.Count; } }
public bool IsReadOnly { get { return _entityCollection.IsReadOnly;} }
public virtual bool IsLoaded
{
get { return _entityCollection.IsLoaded; }
}
public virtual void Load()
{
_entityCollection.Load();
}
public virtual IQueryable<TEntity> CreateSourceQuery()
{
return _entityCollection.CreateSourceQuery();
}
public bool Contains(TInterface entity)
{
return _entityCollection.Contains(entity as TEntity);
}
public void Add(TInterface entity)
{
_entityCollection.Add(entity as TEntity);
}
public bool Remove(TInterface entity)
{
return _entityCollection.Remove(entity as TEntity);
}
public void Clear()
{
_entityCollection.Clear();
}
public void CopyTo(TInterface[] array, int arrayIndex)
{
TEntity[] entitiesArray = null;
_entityCollection.CopyTo(entitiesArray, arrayIndex);
array = entitiesArray.Cast<TInterface>().ToArray();
}
public IEnumerator<TInterface> GetEnumerator()
{
return _entityCollection.Cast<TInterface>().GetEnumerator();
}
//IListSource & IEnumerator implementation were omitted for code clearance
}
Unit Tests for Entities:
Each of ICategory and ISupplier contains IEntityCollection<Product> property called Products. While IProduct has 2 navigation properties for ICategory (Category property) and ISupplier (Supplier property).
For ICategory or ISupplier implementations which would be generated and modified entities Category and Supplier classes, I want to test the following:
- when calling Products property is should class EntityCollectionWrapper.Load method if the products is not already loaded –IsLoaded is false- this should simulate calling to original EntityCollection<TEntity>.Load method.
- When calling ProductCount method, this should trigger EntityCollectionWrapper.CreateSourceQuery method which should simulate calling to original EntityCollection<TEntity>.CreateSourceQuery method.
- When calling Add method of Products property (e.g. category.Products.Add(product)) this should increase Products collection count.
Below is the declaration of CategoryTest Class:
[TestClass]
public class CategoryTest
{
private readonly Category _category;
private readonly Mock<EntityCollectionWrapper<IProduct, Product>> _mockedProducts;
public CategoryTest()
{
_category = new Category();
_mockedProducts = new Mock<EntityCollectionWrapper<IProduct, Product>>(_category.ProductsInternal);
}
//Rest of code omitted and will be discussed later
}
As you notice in the above code line 5, there is a mocked object of EntityCollectionWrapper class that is instantiated in the constructor line 9. But how exactly I am going to set the related field in Category class? Below are the Category class implementation for ICategory interface:
public partial class Category : ICategory
{
private EntityCollectionWrapper<IProduct,Product> _products;
public IEntityCollection<IProduct> Products
{
get
{
EnsureProducts();
if (!_products.IsLoaded)
{
_products.Load();
}
return _products;
}
}
public int ProductCount
{
get
{
EnsureProducts();
return _products.CreateSourceQuery().Count();
}
}
private void EnsureProducts()
{
if (_products == null)
{
_products = new EntityCollectionWrapper<IProduct, Product>(this.ProductsInternal);
}
}
/// <summary>
/// Helper method used for unit testing purpose only to set Mocked EntityCollectionWrapper
/// to local private object _products.
/// </summary>
/// <param name="mockedProducts">Mock object of EntityCollectionWrapper</param>
internal void SetMockedEntityCollection(EntityCollectionWrapper<IProduct,Product> mockedProducts)
{
_products = mockedProducts;
}
}
Last method on line 40 is internal method that is used only for testing purpose to assign a mocked instance of EntityCollectionWrapper to the local private member of the same type.
Also It worth to mention that the generated EntityCollection<Product> property which called here ProductsInternal has internal access modifier, because this is also is being used internally as well as from the testing project.
Now back to CategoryTest class, I am using the following method as my test initialization method:
[TestInitialize]
public void TestInitialize()
{
_category.SetMockedEntityCollection(_mockedProducts.Object);
}
Simply it makes a call to the internal method
SetMockedEntityCollection and pass the mocked object as parameter to it. Now that I have a mocked object injected into my class I can start setup my results to continue testing.
[TestMethod]
public void Category_Products_Should_Call_EntityCollection_Load_If_ProductsInternal_Not_Loaded()
{
_mockedProducts.SetupGet(p => p.IsLoaded).Returns(false).Verifiable();
_mockedProducts.Setup(p => p.Load()).Verifiable();
IEntityCollection<IProduct> products = _category.Products;
_mockedProducts.Verify();
}
In the above code I am testing lazy loading. If the collection is not loaded Load method of the EntityCollection should be called. At line 4 I set assumption that EntityCollectionWrapper<IProduct,Product>.IsLoaded should return false. And as this property must be called I’m asking to verify that it will be called using Verifiable method. At line 5 I am asking to verify that Load method is being called. Finally line 8 when calling Verify method, all verifiable calls will be evaluated and if one of the verifiable calls never occur and exception will be thrown and the test method will fail.
The other 2 tests that I motioned earlier are below:
[TestMethod]
public void Category_ProductCount_Should_Call_EntityCollection_CreateSourceQuery()
{
IList<Product> products = new List<Product>();
_mockedProducts.Setup(p => p.CreateSourceQuery()).Returns(products.AsQueryable()).Verifiable();
int count = _category.ProductCount;
_mockedProducts.Verify();
}
[TestMethod]
public void Category_Add_Product_To_Products_Collection_Should_Increase_Collection_Count()
{
_category.Products.Add(new Product());
Assert.AreEqual(1, _category.Products.Count);
}
I think I delivered my idea here. So you can explore the attached solution for the rest of unit tests of both entities Product and Supplier. Supplier is exactly the same as Category.
I next post I will provide code for integration testing this. Just to make sure that this is really going to work with Entity Framework. For the time being, trust me it does work.
Download Sample Project.