Click here to Skip to main content
Click here to Skip to main content

Mocking the generic repository

By , 29 Jul 2012
 
This post describe one way to mock the generic repository. It assumes that you are familiar with the
Service <-> Repository <-> Database architecture.
Another pre-requisity is the knowledge of the repository pattern and it's generic variant.

In the majority of my projects I am using the following generic repository class.
public interface IRepository
{
 T Load<T>(object id);
 T Get<T>(object id);
 IEnumerable<T> Find<T>(Expression<Func<T, bool>> matchingCriteria);
 IEnumerable<T> GetAll<T>();
 void Save<T>(T obj);
 void Update<T>(T obj);
 void Delete<T>(T obj);
 void Flush();
 int CountAll<T>();
 void Evict<T>(T obj);
 void Refresh<T>(T obj);
 void Clear();
 void SaveOrUpdate<T>(T obj);
}

Based on this technique, some people decide to implement concrete classes of this interface (CarRepository : IRepository), whereas others decide to keep using the generic implementation. That depends on the ORM that you are using. With EF and NHibernate you can easily implement the generic variant of the repository (check the links).

I am also using the generic variant (mostly with NHibernate). Now the question is: How to mock this generic repository? It can be a bit tricky to mock. When you have one class for each repository which works for one concrete type you can mock the repository quite easily. For example StudentRepository which handles entities of type Student might be backed up a list of students.

While when working with generic repository, it might be a bit harder. Here is how I have solved the problem:

public class MockedRepository :IRepository
{
 public MockedRepository()
 {
  cities = DeserializeList<city>("CityDto");
  stations = DeserializeList<station>("StationDto");
  tips = DeserializeList<informationtip>("InformationTipDto");
  countries = DeserializeList<country>("CountryDto");
  
  dataDictionary = new Dictionary<type,object>();
  dataDictionary.Add(typeof(City), cities);
  dataDictionary.Add(typeof(Station), stations);
  dataDictionary.Add(typeof(InformationTip), tips);
  dataDictionary.Add(typeof(Country), countries);
  }   

 public T Get<T>(object id)
 {
  Type type = typeof(T);
  var data = dataDictionary[type];
  IEnumerable<T> list = (IEnumerable<T>)data;
  var idProperty = type.GetProperty("Id");
  return list.FirstOrDefault(x=>(int)idProperty.GetValue(x,null) == (int)id);
 }

 public IEnumerable<T> Find<T>(Expression<Func<T, bool>> matchingCriteria)
 {
  Type type = typeof(T);
  var data = dataDictionary[type];
  IEnumerable<T> list = (IEnumerable<T>)data;
  var matchFunction = matchingCriteria.Compile();
  return list.Where(matchFunction);
 }

 public IEnumerable<T> GetAll<T>()
 {
  Type type = typeof(T);
  return (IEnumerable<T>)dataDictionary[type];
 }

 public void Save<T>(T obj)
 {
  Type type = typeof(T);
  List<T> data = (List<T>)dataDictionary[type];
  data.Add(obj);
 }
}
The main building block of this mocked repository is the dictionary which contains for each type in the repository the enumerable collection of objects. Each method in the mocked repository can use this dictionary to determine which is the collection addressed by the call (by using the generic type T.).
Type type = typeof(T);
var data = dataDictionary[type];
IEnumerable<T> list = (IEnumerable<T>)data;
Now what to do next, depends on each method. I have shown here only the methods which I needed to mock, but the other ones should not be harded to mock. The most interesting is the Find method, which takes as the parameter the matching criteria. In order to pass this criteria to the Where method on the collection, this criteria (represented by an Expression) has to be compiled into a predicate Func (in other words function which takes an object of type T and returns boolean value.

The Get also has some hidden complexity. In this implementation I assume, that there is a Id property defined on the object of type T. I am using reflection to obtain the value of that property and the whole thing happens inside the a LINQ statement.

This repository might be useful, but it is definitely not the only way to isolate your database. So the question is - Should this be the method to isolate my Unit or Integration tests? Let's take a look at other possible options:

  • Use mocking framework (there is quite a choice here)
    This essentialy means that in each of your tests you define the behaviour of the repository class. This requires you to write a mock for each repository method that is called inside the service method. So it means more code to write. On the other hand you controll the behaviour needed for the particular tested method. While using mocking framework you have also the option to verify that methods have been caled.
  • Use the repository implementation and point it to in-memmory database (SQL Lite). That is a good option in the case when:
    • You are able to populate the database with the data.
    • You are sure of your repository implementation
  • Use the generic repository mock presented here. That is not a bad option if you have some way to populate the collections which serve as in-memmory database. I have used deserialization from JSON. Another option could be to use a framework such as AutoPoco to generate the data. You can also create one repository which can be used for the whole test suite (or application presentation).

Summary

As said before this might be a variant to consider. I am using it for Proof of Concepts and portable versions of database based applications. On the other hand for unit test you might consider either mocking framework or in-memory database. There is no clear winner in this comparison.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Jan Fajfr
Software Developer (Junior) OCTO Technology
Czech Republic Czech Republic
I work as IT consultant at OCTO Technology. Previously I have lived and studied CS in Prague, Paris and Valencia.
 
LinkedIn
Blog
GitHub
Articles at OCTO blog

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralI may be missing something but why would you not domvpSacha Barber10-Jul-12 5:18 
Something like this
 
Where you have a IRespository implementation like this
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.Linq.Expressions;
using System.ComponentModel.Composition;
 
namespace Restful.Entities
{
    public class Repository<T> : IRepository<T> where T : class
    {
        protected IUnitOfWork context;
 
        public void EnrolInUnitOfWork(IUnitOfWork unitOfWork)
        {
            this.context = unitOfWork;
        }
 
        public int Count
        {
            get { return context.Get<T>().Count(); }
        }
 
        public void Add(T item)
        {
            context.Add(item);
        }
 
        public bool Contains(T item)
        {
            return context.Get<T>().FirstOrDefault(t => t == item) != null;
        }
 
        public void Remove(T item)
        {
            context.Remove(item);
        }
 
        public IQueryable<T> FindAll()
        {
            return context.Get<T>();
        }
 
        public IQueryable<T> FindAll(Func<DbSet<T>, IQueryable<T>>
 
Which you can them use like this
 
[ServiceContract]
[Export]
public class EFResource  : IDisposable
{
    IUnitOfWork unitOfWork;
    IRepository<Author> authorsRep;
    IRepository<Book> booksRep;
    ILoggerService loggerService;
 
    [ImportingConstructor]
    public EFResource(
        IUnitOfWork unitOfWork,
        IRepository<Author> authorsRep)
    {
        this.unitOfWork = unitOfWork;
        this.authorsRep = authorsRep;
    }
 
    ....
    ....
    ....
    ....
}
 

Where its configured in IOC container like this (I am using MEF)
 
context.ForType(typeof(Repository<>))
        .Export(builder => builder.AsContractType(typeof(IRepository<>)))
        .SetCreationPolicy(CreationPolicy.NonShared);
 

This allows me to use a Generic repository with an open generic in my IOC container (MEF CompositionContainer), which I then satisfy where I use it.
 
Then in my tests I can just use a test double of IRepository<Author> or use mocking frameworks such as Moq to setup what the repository should return.
 
I talk about in detail here : RESTful WCF / EF POCO / Unit of Work / Repository / MEF: 1 of 2
 

I am not having a go at all, its just perhaps I don't understand your problem, I think using open generics / Generic Repository is ok to test, no?
Sacha Barber
  • Microsoft Visual C# MVP 2008-2012
  • Codeproject MVP 2008-2012
Open Source Projects
Cinch SL/WPF MVVM

Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue
 
My Blog : sachabarber.net

GeneralRe: I may be missing something but why would you not domemberJan Fajfr22-Jul-12 22:58 
Hello Sacha,
 
I needed a way to create a portable demo of my applicaiton. The application was using the generic repository as I have described.
 
What I needed was to backup a repository by sevaral enumerations. Something like in-memory database in C#. I had some data in JSON (just lines of tables) and I knew that I can deserailize it into lists or any IEnumerable. And I wanted my generic repository to work with this data.
 
Your implementation of the repository pattern using the open generics and exposing Queryable is probably better. But I did not want to talk about that.
 
What I wanted to was just to do a portable version of the application which could be used without database just by pluging a complete mock of the repository.
 
So the solution to me was to have a dictionary containing the enumarations of all entities and use the type to decided which enumeration should be queried/updated. The most interesting part is I think just this:
 
public IEnumerable Find(Expression> matchingCriteria)
{
Type type = typeof(T);
var data = dataDictionary[type];
IEnumerable list = (IEnumerable)data;
var matchFunction = matchingCriteria.Compile();
return list.Where(matchFunction);
}
 
First I use the type of the parameter to decide which enumeration should be queried and than the query is passed directly to this enumeration.
 
Actualy this is not that helpful for testing, because as you said with any mocking framework you can specify the return of any method. But for a demo version of a applicaiton it might be quiete useful.
 
Do you know any other way to plug your generic repository to data loaded from JSON or XML just for demo in-memmory version of your application?
 
This just came to my spirit, but there is surely a better way.
 
Cheers,
Jan
QuestionGood pattern, questions on change notificationmemberTopchris24-Jun-12 2:27 
Hello Jan, nice article and example of using IRepository.
 
Suppose that the Repository needed to notify observing members of changes to its data, how would you implement that? Would this require usage of Observable or possibly the Reactive Extensions framework?
AnswerRe: Good pattern, questions on change notificationmemberJan Fajfr22-Jul-12 23:06 
Hello,
 
I am not sure why you would need an "observable" repository. Repository should be just a gateway to the database. It does not have the info about changes in the database. Imagine there is some other application which inserts data into the database. Your repository will never get a message about that.
 
Of course in the case of a in-memory repository just like the one that I have shown it would be possible just by adding an event which would be raised any time there is a change. But that is not specified by the "repository" interface. And if this would be in the interface, than no one could actually build an implementation of real repository which would comply to this.
 
What is your use case? If you need this for updating the UI, than this should be done in the upper layers. If you are using MVVM pattern, than this should be taken care of in the ViewModel by using ObservableCollection.
 
If you are building real-time event processing system - than you have to go for CEP processing engine and not just a simple DB interaction application I think.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130617.1 | Last Updated 29 Jul 2012
Article Copyright 2012 by Jan Fajfr
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid