简体   繁体   English

如何使我的存储库和工作单元脱钩以使其可测试

[英]How to decouple my repositories and unitofwork in order to make them testable

实际上,我已经以这种方式实现了我的存储库和工作单元,并且我还发现了Qujck先生关于我的问题的翔实的回答 ,这在很大程度上帮助了我,但是我唯一的问题是,根据他的回答,该主题中我不知道我应该如何以及在哪里实施CRUD操作。我也有这个问题尚未得到解答。如果有人可以帮助我,我将不胜感激。

EntityFramework already provides you with all the functionality regarding CRUD operations, and generally speaking, you don't need to test EntityFramework, because we just assume that it works. EntityFramework已经为您提供了有关CRUD操作的所有功能,通常来说,您不需要测试EntityFramework,因为我们只是假设它可以工作。 The way it is shown in that website, is that you create a higher abstraction layer than simple CRUD operations, build it on top of EF, and call it Repository (Data access layer). 它在该网站上显示的方式是,您创建比简单的CRUD操作更高的抽象层,将其构建在EF之上,并将其称为Repository (数据访问层)。 So in this case, you only need to make sure that you DAL (aka Repository in this case) is decoupled. 因此,在这种情况下,您只需要确保DAL(在这种情况下又称为存储库)已解耦。 The only thing repository is coupled to is EntityFramework's DbContext, which, is not realy decouplable from, so the lowest level of abstraction that you realy need to test and decouple upwards is your Repository class. 唯一与存储库关联的是EntityFramework的DbContext,它确实不可与之分离,因此您真正需要向上测试和分离的最低抽象层是您的Repository类。

The way the Unit Of Work pattern is being employed in that example does not truly represent how a UoW should behave. 在该示例中采用工作单位模式的方式并不能真正代表UoW的行为方式。 The repositories should have knowledge of the UoW, but the UoW should not have any reference to your repositories. 存储库应该了解UoW,但是UoW不应该引用您的存储库。 The UoW should only know about your context. UoW应该只知道您的上下文。 In my example below, you remove the repository dependencies from the UoW. 在下面的示例中,您将从UoW中删除存储库依赖项。 For testing, you could implement a fake DbContext if you really needed to, bu that may be overkill. 对于测试,如果您确实需要,可以实现一个伪造的DbContext,但这样做可能会过大。

Another suggestion I have is to add one further abstraction to your repositories and create a Service layer. 我的另一个建议是向您的存储库添加另一个抽象,并创建一个Service层。 This will act as your Business layer and these would be injected into your MVC controllers. 这将充当您的业务层,并将这些注入到您的MVC控制器中。 This way, if you work with DTOs or view models, you can map betwen entities and DTO in that layer so the application will never really expose your underlying DAL. 这样,如果您使用DTO或查看模型,则可以在该层中映射实体和DTO,这样应用程序将永远不会真正暴露您的基础DAL。

    public interface IUnitOfWork : IDisposable
    {
        /// <summary>
        /// Flushes content of unit of work to the underlying data storage. 
        /// Causes unsaved entities to be written to the data storage.
        /// </summary>
        void Flush();

        /// <summary>
        /// Begins the transaction.
        /// </summary>
        ITransaction BeginTransaction();

        /// <summary>
        /// Ends transaction.
        /// Note: suggested pattern to manage a transaction is via *using* construct.
        /// You should set input param to null after calling the method.
        /// </summary>
        /// <example>
        /// using ( var tnx = uow.BeginTransaction() ) { /* do some work */ }
        /// </example>
        /// See also <seealso cref="ITransaction"/> interface for more details.
        void EndTransaction(ITransaction transaction);

        /// <summary>
        /// Inserts entity to the storage.
        /// </summary>
        void Create<TEntity>(TEntity entity) where TEntity : class;

        /// <summary>
        /// Updates entity in the storage.
        /// </summary>
        void Update<TEntity>(TEntity entity) where TEntity : class;

        /// <summary>
        /// Updates entity in the storage.
        /// </summary>
        void Merge<TEntity>(TEntity original, TEntity current) where TEntity : class;


        /// <summary>
        /// Deletes entity in the storage.
        /// </summary>
        void Delete<TEntity>(TEntity entity) where TEntity : class;


    }

    public interface IRepository<TEntity> where TEntity: class
    {
        void Create(TEntity entity);
        TEntity GetById(object id);
        IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> criteria);
          IEnumerable<TEntity> GetAll();
        void Delete(object id);
        void Delete(TEntity entity);
        void Update(TEntity entity);
        void Merge(TEntity original, TEntity current);
        IUnitOfwork UnitOfWork { get; }
    }




    public class EntityFrameworkUnitOfWork: DbContext, IUnitOfwork
    {
        public virtual void Flush()
        {
            //The DbContext Save Changes method..
            SaveChanges();
        }    

        public virtual void Create<TEntity>(TEntity entity) where TEntity : class
        {
            base.Set<TEntity>().Add(entity);
        }

       ..other method implementations...
     }


 public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        private readonly IUnitOfWork _unitOfWork;

        public Repository(IUnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }

        ...other method implementations...
    }

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

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