代码之家  ›  专栏  ›  技术社区  ›  Grant Palin Bob King

单元测试应该知道NHibernate吗?

  •  0
  • Grant Palin Bob King  · 技术社区  · 15 年前

    a previous question . 我接受的答案是使用泛型 IRepository 为了处理基本的CRUD,用特定于域的 IMovieRepository 委托给常规设置。进一步的细节包括 WrapQueryInSession 间接的

    IEnumerable<T> WrapQueryInSession(Func<ISession, IEnumerable<T>> query);
    

    当我意识到这暴露了NHibernate ISession 间接的 实现,但对于该方法签名。

    当我想进行单元测试时,这一点就显得尤为重要 MovieRepository 间接的 ,实施于 RepositoryFake 电影摄影棚

    protected override void BeforeEachTest()
    {
        _fixture = new MovieRepository(new RepositoryFake());
    }
    

    我的测试类有一个私有的假存储库实现:

    private class RepositoryFake : IRepository<Movie>
    {
        ...
        public IEnumerable<Movie> WrapQueryInSession(Func<ISession, IEnumerable<Movie>> query)
        {
            ...
        }
        ...
    }
    

    间接的 实施,就是要意识到 ISession公司 从NHibernate,因此NHibernate本身。这似乎是一个漏洞百出的抽象。

    有没有更好的方法来完全控制NHibernate的使用 间接的 实施?

    2 回复  |  直到 9 年前
        1
  •  2
  •   Community Mohan Dere    9 年前

    这个想法来自 my answer to your previous question 一般的IRepository只在您的基础结构层中知道—它不会在这个层之外发布。当您将ISession发布到非泛型存储库时,它们将获得一个非常通用的接口,因为它们可以访问ISession进行查询。不公开ISession的问题是,您的通用存储库将:

    1. 有一大堆不同的查询方法(基本上是复制ISession的接口)。

    将NHibernate的查询接口隐藏在facade中似乎有点浪费(一般存储库仅限于此)。

    在我看来,如果您选择nHibernate,您应该利用它所提供的功能,并在整个基础结构dll(包括测试)中保持依赖性。将泛型IRepository接口看作NHibernate的助手接口,以减少存储库中重复代码的数量。

        2
  •  2
  •   tolism7    15 年前

    我同意NHibernate不应该被完全抽象的原则,但是我发现NHibernate的查询接口可以被隐藏起来而不需要太多的麻烦,这可以通过使用查询对象来实现。

    每个查询对象都应该利用NHibernate提供的功能(ISession、ICriteria、IQuery等),并且可以通过实现IRepository来执行。

    public interface IRepository
    {
            ISession Session { get; }
            TResult Query<TResult>(IQuery<TResult> query);
    }
    
    public class Repository : IRepository
    {
        public ISession Session
        {
            get { return /* Call the session factory to return an ISession */; }
        }
    
        public TResult Query<TResult>(IQuery<TResult> query)
        {
            return query.Execute(Session));
        }
    }
    
    public interface IQuery<TResult>
    {
        TResult Execute(QueryContext context);
    }
    
    public abstract class Query<TResult> : IQuery<TResult>
    {
        public abstract TResult Execute(ISession session);
    }
    
    public class GetPeopleByName: IQuery<Person>
    {
        private readonly string _name;
    
        public GetPeopleByName(string name)
        {
            _name = name;
        }
    
        public override IList<Person> Execute(ISeesion session)
        {
            var query = context.Session.CreateCriteria(typeof(Person))
                .Add(Restrictions.Eq("Name", _name));
    
            return query.List<Person>();
        }
    }
    

    然后你可以使用上面的公式:

    IRepository repository = /* Get somehow the implementation */
    IList<Person> people = repository.Execute(new GetPeopleByName("Anna"));