mosquito87
mosquito87

Reputation: 4440

Entity Framework: Implement interfaces for unit test

today I wanted to start unit-testing a little asp.net MVC 3 Web (test) application to learn some new stuff.

But things went worse then I had expected ...

I've now read some threads about unit testing in relation with Entity framework and now I first want to implement interfaces for my entity framework related classes so that I can implement an in memory "database" for my unit tests.

My code base is from ASP.NET MVC tutorial. I've read MSDN but it doesn't help me in my cases.

I'd like to show you my code. I'm using a unit of work pattern with repositories:

Unit of work:

public class SqlUnitOfWork : IUnitOfWork, IDisposable
{
    private SqlContext context = new SqlContext();
    private IGenericRepository<Message> messageRepository;
    private IGenericRepository<Receipt> receiptRepository;
    private IGenericRepository<Useraccount> useraccountRepository;
    private bool disposed = false;

    public IGenericRepository<Message> MessageRepository
    {
        get
        {
            if (this.messageRepository == null)
            {
                this.messageRepository = new SqlGenericRepository<Message>(context);
            }
            return messageRepository;
        }
    }

    public IGenericRepository<Receipt> ReceiptRepository
    {
        get
        {
            if (this.receiptRepository == null)
            {
                this.receiptRepository = new SqlGenericRepository<Receipt>(context);
            }
            return receiptRepository;
        }
    }

    public IGenericRepository<Useraccount> UseraccountRepository
    {
        get
        {
            if (this.useraccountRepository == null)
            {
                this.useraccountRepository = new SqlGenericRepository<Useraccount>(context);
            }
            return useraccountRepository;
        }
    }

    public SqlUnitOfWork()
    {
    }

    ~SqlUnitOfWork()
    {
    }

    public virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                context.Dispose();
            }
        }

        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    public void Save()
    {
        context.SaveChanges();
    }
}

This one implements an interface I've created.

My generic repository for sql:

public class SqlGenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
    internal SqlContext context;
    internal DbSet<TEntity> dbSet;

    public SqlGenericRepository(SqlContext context)
    {
        this.context = context;
        this.dbSet = context.Set<TEntity>();
    }

    ~SqlGenericRepository()
    {
    }

    public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, 
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
    {
        IQueryable<TEntity> query = dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }
        else
        {
            return query.ToList();
        }
    }

    public virtual TEntity GetByID(object id)
    {
        return dbSet.Find(id);
    }

    public virtual void Insert(TEntity entity)
    {
        dbSet.Add(entity);
    }


    public virtual void Delete(object id)
    {
        TEntity entityToDelete = dbSet.Find(id);
        Delete(entityToDelete);
    }

    public virtual void Delete(TEntity entityToDelete)
    {
        if (context.Entry(entityToDelete).State == EntityState.Detached)
        {
            dbSet.Attach(entityToDelete);
        }
        dbSet.Remove(entityToDelete);
    }

    public virtual void Update(TEntity entityToUpdate)
    {
        dbSet.Attach(entityToUpdate);
        context.Entry(entityToUpdate).State = EntityState.Modified;
    }
}

It implements an interface I've programmed:

public interface IGenericRepository<TEntity> where TEntity : class
{
    IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "");

    TEntity GetByID(object id);

    void Insert(TEntity entity);

    void Delete(object id);

    void Delete(TEntity entityToDelete);

    void Update(TEntity entityToUpdate);
}

I would now like to implement an "InMemoryGenericRepository" for my unit tests, then an "InMemoryUnitOfWork". How would those "InMemoryGenericRepository" look like?

I think I would use a generic List inside this repository where all data is stored:

IEnumerable<TEntity> List { get; set; }

But how can I adapt this method:

public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
{
    IQueryable<TEntity> query = dbSet;

    if (filter != null)
    {
        query = query.Where(filter);
    }

    foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
    {
        query = query.Include(includeProperty);
    }

    if (orderBy != null)
    {
        return orderBy(query).ToList();
    }
    else
    {
        return query.ToList();
    }
}

so it's working with my

IEnumerable<TEntity> List { get; set; }

I hope you made it until the end of my question.

Upvotes: 3

Views: 870

Answers (3)

usr
usr

Reputation: 171178

The generic repository pattern is not a good pattern. It gets you a lot of pain in exchange for storage independence (which you likely don't need. You like to have it but you don't really need it). You will really have a hard time to write a queryable in-memory repository for a few reasons:

  • the entities have relationships which must be setup correctly
  • in-memory queries behave differently than SQL queries (for example, they are case-sensitive)
  • in-memory queries have no optimizer which can lead to excessive runtime of tests
  • you now have to test the tests, basically, so you can be sure that no difference in behavior exists

Also, by abstracting away your ORM you can use none of its features. You can only use the most generic and general features.

I have done exactly this a few years ago and the pain just doesn't end. I found it to be a good pattern to use a real SQL database for tests. That way you don't need any repository and can test the real thing. This has its problems but it is workable.

The solution to this question is to abandon the generic repository pattern.

Upvotes: 0

abatishchev
abatishchev

Reputation: 100258

Also you could rewrite your lazy properties with:

private IGenericRepository<Message> messageRepository;

public IGenericRepository<Message> MessageRepository
{
    get
    {
        return messageRepository ?? (messageRepository = new IGenericRepository<Message>());
    }
}

or

private Lazy<IGenericRepository<Message>> messageRepository = new Lazy<IGenericRepository<Message>>(new IGenericRepository<Message>()));

public IGenericRepository<Message> MessageRepository
{
    get
    {
        return messageRepository.Value;
    }
}

Upvotes: 0

abatishchev
abatishchev

Reputation: 100258

If your classes are POCO then they're looking like this:

namespace Project.Model // auto-generated Foo.cs
{
    public partial class Foo // notice partiality
    {
    }
}

Then you write this:

namespace Project.Model // custom Foo.cs in another folder
{
    public partial class Foo : IEntity // notice interface
    {
    }
}

Upvotes: 1

Related Questions