EF 4.1 :: Тестирование с Moq & NUnit - PullRequest
1 голос
/ 11 августа 2011

Я использую Entity Framework 4.1 для моего DAL в моем текущем проекте, и сейчас пытаюсь провести модульное тестирование своих бизнес-объектов, одновременно высмеивая мои сущности с помощью moq.

Я создал универсальную единицу работы

public interface IFRSDbContext
{
    IDbSet<Category> Categories { get; set; }
    IDbSet<Cell> Cells { get; set; }
    IDbSet<DealSummary> DealSummaries { get; set; }
    IDbSet<DealSummaryDetail> DealSummaryDetails { get; set; }
    IDbSet<Node> Nodes { get; set; }
    IDbSet<Rto> Rtos { get; set; }
    IDbSet<Sheet> Sheets { get; set; }
    IDbSet<Version> Versions { get; set; }
    IDbSet<VersionMapping> VersionMappings { get; set; }

    DbEntityEntry Entry(object entity); 
    DbSet<TEntity> Set<TEntity>() where TEntity : class;
    int SaveChanges();
}

Как и общий репозиторий

public abstract class Repository<TEntity> where TEntity : class
{
    protected IFRSDbContext DbContext;

    protected Repository(IFRSDbContext context) 
    { 
        DbContext = context;
    } 


    public virtual TEntity GetById(object id)
    {
        return DbContext.Set<TEntity>().Find(id);
    }


    public virtual void Insert(TEntity entity)
    {
        DbContext.Set<TEntity>().Add(entity);
    }


    public virtual void Delete(object id)
    { 
        var entityToDelete = DbContext.Set<TEntity>().Find(id); 
        Delete(entityToDelete); 
    } 


    public virtual void Delete(TEntity entityToDelete)
    {
        DbContext.Set<TEntity>().Remove(entityToDelete);
    }


    public abstract void Update(TEntity entityToUpdate);
}

У меня также есть репозиторий для каждой сущности, вот пример:

public class DealSummaryRepository : Repository<DealSummary>
{
    public DealSummaryRepository(IFRSDbContext context) : base(context) { }


    public virtual DealSummary GetByFileName(string fileName)
    {
        return DbContext.Set<DealSummary>().FirstOrDefault(d => d.FileName == fileName);
    }


    public override void Update(DealSummary entityToUpdate)
    {
        var existingDealSummary = GetByFileName(entityToUpdate.FileName);

        if (existingDealSummary == null)
        {
            var message = string.Format(@"Error :: Cannot update Deal Summary '{0}' because it does not exist
                                        in the database.", entityToUpdate.FileName);

            throw new Exception(message);
        }

        existingDealSummary.DateModified = DateTime.Now;
        existingDealSummary.StartDate = entityToUpdate.StartDate;
        existingDealSummary.EndDate = entityToUpdate.EndDate;
        existingDealSummary.DueDate = entityToUpdate.DueDate;
        existingDealSummary.WasWon = entityToUpdate.WasWon;
        existingDealSummary.UploadedBy = entityToUpdate.UploadedBy;

        if (existingDealSummary.Details != null)
            existingDealSummary.Details.Clear();

        existingDealSummary.Details = entityToUpdate.Details;
    }
}

Вопрос, который у меня естьесть ли способ реализовать объект IDbSet в качестве моего общего репозитория и унаследовать это ... или я должен содержать свои репозитории в моей единице работы, и реализовать IDbSet внутри репозиториев?Единственная проблема, с которой я сталкиваюсь при реализации IDbSet внутри репозитория, заключается в том, что мой репозиторий зависит от EF.

Будем весьма признательны за любые предположения / рекомендации.Я пытаюсь использовать самый простой из возможных подходов, чтобы мои сущности были поддающимися контролю, чтобы я мог тестировать без зависимости от структуры сущностей / моей базы данных.

1 Ответ

3 голосов
/ 11 августа 2011

Я использовал шаблон EF Code First + Repositories из http://efmvc.codeplex.com, у которого есть пара отличий от того, как вы создали свой

Первое, что я заметил, это то, что ваша Единица работы связана с EF. Единица работы EFMVC просто

public interface IUnitOfWork
{
    void Commit();
}

Чтобы не связывать репозитории с EF, у нас есть

public interface IRepository<T> where T : class
{
    void Add(T entity);
    void Update(T entity);
    void Delete(T entity);
    void Delete(Expression<Func<T, bool>> where);
    T GetById(long Id);
    T GetById(string Id);
    T Get(Expression<Func<T, bool>> where);
    IQueryable<T> GetAll();
    IQueryable<T> GetMany(Expression<Func<T, bool>> where);
}

и наша реализация IRepository<T> - это то, что требует зависимости от EF. Так что теперь вместо насмешки IFRSDbContext с IDbSet s (EntityFramework), вы высмеиваете IRepository<T> с IQueryable s (System.Core)

РЕДАКТИРОВАТЬ: На ваш вопрос, это может выглядеть примерно так

public class Uploader : IUploader
{ 
    private readonly IReportRepository _reportRepository; 
    private readonly IUnitOfWork _unitOfWork; 

    public Uploader(IReportRepository reportRepository, IUnitOfWork unitOfWork) 
    { 
        _reportRepository = reportRepository;
        _unitOfWork = unitOfWork;
    }

    public void Upload(Report report)
    {
        _reportRepository.Add(report);
        _unitOfWork.Commit();
    }

}
...