Entity Framework: implementing interfaces for a unit test

Today I wanted to start unit testing a small asp.net MVC 3 Web (test) application to learn some new things.

But things got worse than I expected ...

Now I have read some threads about unit testing regarding Entity framework, and now I first want to implement interfaces for related entity framework classes so that I can implement an in memory database for my unit tests.

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

I want to show you my code. I use the repository pattern unit:

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 tool implements the interface that I created.

My shared 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 the interface that I have 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);
}

      

Now I would like to implement "InMemoryGenericRepository" for my unit tests and then "InMemoryUnitOfWork". What does this "InMemoryGenericRepository" look like?

I think I would use a generic list inside this repository where all the 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 works with mine

IEnumerable<TEntity> List { get; set; }

      

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

+3


source to share


3 answers


The general repository pattern is not a good pattern. It saves you the pain in exchange for storage independence (which you most likely don't need. You like having it, but you really don't need it). You will actually find it harder to write the requested in-memory repository for several reasons:

  • objects have relationships that need to be configured correctly.
  • in-memory queries behave differently than SQL queries (for example, they are case sensitive)
  • There is no optimizer in memory queries, which can lead to excessive test execution time.
  • you need to test your tests first, so you can be sure there is no difference in behavior.

Also, by abstracting your ORM, you cannot use any of its features. You can only use the most general and general functions.



I did just that a few years ago and the pain just doesn't end. I found this to be a good pattern for using a real SQL database for tests. This way you don't need any repository and it can reality check. This has its problems, but it is workable.

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

0


source


If your classes are POCO they look 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
    {
    }
}

      

+1


source


Also you can 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;
    }
}

      

0


source







All Articles