简体   繁体   English

EF 4.1:: 使用 Moq 和 NUnit 进行测试

[英]EF 4.1 :: Testing with Moq & NUnit

I am using Entity Framework 4.1 for my DAL on my current project, and am now trying to unit test my business objects while mocking my entities with moq.我在我当前的项目中为我的 DAL 使用 Entity Framework 4.1,现在我正在尝试对我的业务对象进行单元测试,而 mocking 我的实体具有最小起订量。

I have created a generic Unit of Work我创建了一个通用的工作单元

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();
}

As well as a generic Repository以及通用存储库

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);
}

I also have a repository for each entity, here is an example:我还为每个实体都有一个存储库,这是一个示例:

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;
    }
}

The question that I have is, is there a way to implement the IDbSet object as my generic repository and inherit that... or should I contain my repositories in my unit of work, and implement the IDbSet inside of the repositories?我的问题是,有没有办法将 IDbSet object 实现为我的通用存储库并继承它......或者我应该在我的工作单元中包含我的存储库,并在存储库中实现 IDbSet? The only problem I have with implementing the IDbSet inside of the repository is then my repository is dependant on EF.在存储库中实现 IDbSet 的唯一问题是我的存储库依赖于 EF。

Any sugguestions/best practices would be greatly appreciated.任何建议/最佳实践将不胜感激。 I am trying to take the simplest approach possible to make my entities mockable so I can test without the dependency to entity framework/my database.我正在尝试采用最简单的方法使我的实体可模拟,这样我就可以在不依赖实体框架/我的数据库的情况下进行测试。

I've been using the EF Code First + Repositories pattern from http://efmvc.codeplex.com which has a couple differences from the way you've constructed yours我一直在使用http://efmvc.codeplex.com中的 EF Code First + Repositories 模式,这与您构建的方式有一些不同

First thing I noticed is your Unit of Work is tied to EF.我注意到的第一件事是您的工作单元与 EF 相关联。 EFMVC's Unit of Work is simply EFMVC 的工作单元很简单

public interface IUnitOfWork
{
    void Commit();
}

To avoid tying the repositories to EF, we have为了避免将存储库绑定到 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);
}

and our implementation of IRepository<T> is what requires the dependency on EF.而我们对IRepository<T>的实现需要对 EF 的依赖。 So now instead of mocking IFRSDbContext with its IDbSet s (EntityFramework), you mock an IRepository<T> with its IQueryable s (System.Core)所以现在代替 mocking IFRSDbContext和它的IDbSet s (EntityFramework),你模拟一个IRepository<T>和它的IQueryable (System.Core)

EDIT: To your question, it might look something like this编辑:对于你的问题,它可能看起来像这样

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();
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM