Introduction
One of the challenging things with current version of Entity Framework, its leakage of testability. Which means when you build an application or module (e.g. Repositories) that depends on entity framework, it will be very hard to unit test your code isolated from Entity Framework. This might lead to conduct Integration Testing which will require a connection and interaction with underlying data store (database).
You might think of using Mocking to mock or fake Entity Framework data store dependent calls. But sadly Moq and Rhino Mock mocking frameworks do not support this. And you’ll end up hitting the wall. Both frameworks are great useful and I personally use Moq for a while now and very happy with it. But no one can deny limitations when exist.
And personally I was able to overcome the limitation of the testability of Entity Framework while I was working in KiGG Entity Framework based models and repositories. But done that through unnecessary code refactoring and wrappers around none mockable classes such as sealed class EntityCollection<T>.
Finding a solution with TypeMock Isolator
In fact there is a solution, that will save you lots of workarounds and unnecessary code refactoring. You just need a full isolation framework. TypeMock Isolator provides this capability. It allows to mock sealed classes and classes that have private constructors, static methods, and much more.
TypeMock isolator makes it easy to simulate and break the dependencies of any object in your existing code. In that way, it doesn’t force you to think about how your design might need to change. –The Art of Unit Testing book page 132-
So, TypeMock isolator is a perfect mate for testing code that has dependencies on Entity Framework as how I am going to show now.
The Sample, snippet from KiGG
I am going to demonstrate how to use TypeMock isolator with Entity Framework through reflected model from KiGG project. Will use some code snippets from it and present single Repository class (class under test) and its Unit Testing class code. I’ll be using xUnit as my Unit Testing framework for simplicity.
Entity Framework Generated ObjectContext
After generating part of KiGG using Entity Framework wizard, an ObjectContext class is generated and it I called it KiGGEntityContainer. I added/enhanced the functionality of generated class by adding few methods such as InsertOnSubmit<TEntity>(TEntity entity) and DeleteOnSubmit<TEntity>(TEntity entity) methods.
public void InsertOnSubmit<TEntity>(TEntity entity)
where TEntity : EntityObject
{
string entitySetName = GetEntitySetName(typeof(TEntity));
AddObject(entitySetName, entity);
}
public void DeleteOnSubmit<TEntity>(TEntity entity)
where TEntity : EntityObject
{
DeleteObject(entity);
}
In the above InsertOnSubmit method it calls a helper method GetEntitySetName. This method retrieve EntitySet name from the meta data.
Nothing to talk about more in this class, The test of this class is out of scope now as it will require access to EDM meta data. So for now it just directs calls to Entity Framework relevant methods AddObject & DeleteObject.
BaseRepository Class
A base generic class for all repositories. Very simple and contain basic functionality. There is nothing to test in this class as it has no logic at all. I’ll add its code for reference only and clarity.
public abstract class BaseRepository<TEntity>
where TEntity : EntityObject
{
private readonly KiggEntityContainer _context;
protected BaseRepository(KiggEntityContainer context)
{
_context = context;
}
protected internal KiggEntityContainer DataContext
{
get
{
return _context;
}
}
public virtual void Add(TEntity entity)
{
DataContext.InsertOnSubmit(entity);
}
public virtual void Remove(TEntity entity)
{
DataContext.DeleteOnSubmit(entity as TEntity);
}
}
Model Class Under Test, Story class
Story is an entity model class. It has 3 navigations properties linking it with other 3 entities (User, Category
and Tag).
Current version of Entity Framework doesn’t support transparent lazy loading. Only eager loading and explicit loading are supported. To over come this limitation, I marked the exiting navigation properties as internal. And made another properties that will handle the logic of loading related end if not already loaded just as the following:
public partial class Story
{
public ICollection<Tag> Tags
{
get
{
if(!TagsInternal.IsLoaded)
{
TagsInternal.Load();
}
return TagsInternal;
}
}
public Category Category
{
get
{
if(!CategoryInternalReference.IsLoaded)
{
CategoryInternalReference.Load();
}
return CategoryInternalReference.Value;
}
}
}
The above 2 properties will need to be tested as they contain logic. What I need to test here is when IsLoaded property of EntityCollection<Tag> (TagsInternal) Or EntityReference<Category> (Category) returns false, Load() method must be called. And if it return false, Load() method mustn’t be called. Here is the first test method –code is commented for clarification-
[Fact]
public void Tags_Should_Call_Load_When_IsLoaded_Is_False()
{
// Arrange
var story = new Story(); //Live Object
//Fake the return of IsLoaded property of EntityCollection<Tag>
Isolate.WhenCalled(() => story.TagsInternal.IsLoaded)
.WillReturn(false);
//Fake the call of Load method by ignoring the call.
//Not doing so will throw an exception because
//Load is supposed to load data from data store.
Isolate.WhenCalled(() => story.TagsInternal.Load())
.IgnoreCall();
#pragma warning disable 168
//Act: Issue call to Tags property
ICollection<Tag> tags = story.Tags;
#pragma warning restore 168
//Assert: Verify that Load method has been called.
Isolate.Verify
.WasCalledWithAnyArguments(()=>story.TagsInternal.Load());
}
What exactly TypeMock Isolator provided me here?
- It was impossible with any other Mocking framework to fake method calls on live object (real object not faked) or one of its properties. In this case the live object the story instance.
- Faking EntityCollection<T> or any of its properties or methods also impossible with other Mocking frameworks, because the class is sealed! TypeMock totally isolate me from Entity Framework by giving the ability to fake Entity Framework types and dependent method calls such as calling IsLoaded property of EntityCollection<T> and Load() method.
As you see, TypeMock isolates my entity class test from Entity Framework although it depends on it. The rest of this StoryFixture test class is included in the attached sample.
The Class Under Test, CategoryRepository
In this class I have 5 methods which I need to test. 3 or them concerns with LINQ to Entities queries and the other 2 are for Add and Remove, both of these 2 methods contains logic that I must be tested. For sample I’ll introduce the Add method:
public override void Add(Category category)
{
if (DataContext.Categories.Any(c => c.Name == categoryName))
{
throw new ArgumentException("Some Error Message...", "category");
}
category.UniqueName = UniqueNameGenerator.GenerateFrom(DataContext.Categories, category.Name);
base.Add(category);
}
The Add method checks if the name exists in the data source or not. If exists an exception should be thrown. If not a unique name to be generated for the category and then to be added to current ObjectContext for later saving.
Issues with testing such method is that it depends on Entity Framework. And current version of Entity Framework will require a database hit to evaluate this query “DataContext.Categories.Any(c => c.Name == categoryName)”!!
Again TypeMock is a saver here. TypeMock is able to fake any ObjectContext instance. Which is not supported by other mocking engines. Faking ObjectContext instance and having the ability to fake all of its method calls and properties is really great thing. I missed that with Moq!
First test for this method is to check if an exception is thrown when a new category is added and there is existing one with the same name –Code commented for clarification-:
[Fact]
public void Add_Existing_Category_Should_Throw_ArgumentException()
{
//Fake KiggEntityContainer -ObjectContext-
var context = Isolate.Fake
.Instance<KiggEntityContainer>(Members.ReturnRecursiveFakes);
//Fake call to dependecy static method on static class UniqueNameGenerator
Isolate.Fake
.StaticMethods<UniqueNameGenerator>(Members.ReturnRecursiveFakes);
var repo = new CategoryRepository(context);
//Create In memory list of categories
var inMemoryCategories = new List<Category>
{
new Category{Name = "Dummy1"},
new Category{Name = "Dummy2"}
};
//Fetch existing category name
string name = inMemoryCategories[0].Name;
//Fake the return of ObjectQuery<T> "context.Categories"
//Instade of using physical datastore I'm using In Memory Store
//LINQ to Entites will be simulated with LINQ to Objects
Isolate.WhenCalled(() => context.Categories)
.WillReturnCollectionValuesOf(inMemoryCategories.AsQueryable());
//Assert
Assert.Throws(typeof(ArgumentException),
() => repo.Add(new Category { Name = name }));
}
Line 5 using fluent AAA (Arrange-Act-Assert) TypeMock APIs to fake an instance -Mock- of KiggEntityContainer object context class. If you tried to do this with Moq for example you’ll desperately receive and exception that EDM meta data couldn’t be loaded. Note here that I also don’t care about the constructor parameters. I like this total isolation.
Line 9 I am faking –subbing- a call to as static method on some static class. I just need to fake its call, and this test doesn't really care about its returned value
Line 14 I am creating an in memory collection of categories. which will be used in replacement for underlying data store as we will see.
Line 26 the most important line. In this line the powerful of TypeMock shown. Here I’m able to fake the return value of ObjectQuery<Category> “context.Categories”. So simply they like says when calling context.Categories return the in memory collection of categories “inMemoryCategories”. There is a trick on this line of code to make it work; I have to call AsQueryable() of the replacement collection. If I didn’t I’ll receive and exception.
Finally Line 30, Asserting that an exception is thrown when call Add method of CategoryRepository instance when passing a new Category with a name that match an existing category in the underlying data source.
Another method in CategoryRepository which is FindByUniqueName is used to retrieve a category by its unique name here is the method:
public Category FindByUniqueName(string uniqueName)
{
return DataContext.Categories.FirstOrDefault(c=>c.UniqueName == uniqueName);
}
Very simple method with no logic! So what exactly I need to test here? Zooming into code, you’ll notice that I want to a category when its unique name matches a specific input. I want to test this LINQ expression that it yields the correct results.
Here is the test method
[Fact]
public void FindById_Should_Return_Correct_Category()
{
//_context is a fake ObjectContext instance
var repository = new CategoryRepository(_context);
//In memory collection store of categories
List<Category> inMemoryCategories = new List<Category>
{
new Category{Id=Guid.NewGuid(),Name = "Dummy1"},
new Category{Id=Guid.NewGuid(),Name = "Dummy2"}
};
Guid id = inMemoryCategories[0].Id;
//Fake ObjectQuery<Category>
//Must call AsQueryable() extension in order for this to work
Isolate.WhenCalled(() => _context.Categories)
.WillReturnCollectionValuesOf(inMemoryCategories.AsQueryable());
//Act
Category found = repository.FindById(id);
//Assert
Assert.Equal(id, found.Id);
}
Again I am replacing (faking) the return of ObjectQuery<Category> with in memory list of categories. This way when _context.Categories is called an in memory IQueryable<Category> will be returned. The LINQ will be evaluated as LINQ to Object an not as LINQ to Entities. Because LINQ to Entities will require a database hit which I want to avoid.
This way TypeMock Isolator provided an isolation from Entity Framework, although my component is totally dependent on Entity Framework. This is impossible with other mocking framework which shows the strength of TypeMock in this point.
Code for this sample downloadable from here. Note that I didn’t include TypeMock assemblies which you should download from here
Conclusion
There is a white paper published by TypeMock with comparing different mocking framework to TypeMock itself. This comparison white paper is downloadable from here. Also there is an open source project to compare between mocking frameworks which you can check it out here.
I’ve been working with different mocking framework for a while now. Moq is my favourite free open source one. I also worked a little with Rhino Mock, a great framework however at the time I was working Moq, I didn’t feel comfortable with record & replay mode of Rhino Mock. Beside Moq was very simple and very easy to learn. Rhino Mock is going to rock in its upcoming version 4.0 you can read about its plans here.
TypeMock is the most powerful mocking framework I ever seen so far. as I mentioned earlier TypeMock isolator makes it easy to simulate and break the dependencies of any object in your existing code. In that way, it doesn’t force you to think about how your design might need to change. –The Art of Unit Testing book page 132-.
TypeMock can isolate almost everything, they even have specific release for unit testing with SharePoint which so far no tool compete on this with it.
TypeMock is commercial, However, they provide free license for open source projects. And for MVPs, they are eligible for a free version TypeMock Isolator Enterprise Edition! MVPs can check it out here.
Download the Sample