如何使用结构图模拟基类?

时间:2017-08-10 09:04:06

标签: nhibernate dependency-injection mocking fluent-nhibernate structuremap

我正在使用NHibernate并拥有许多存储库,这些存储库都继承自基本的NHibernateRepository类。这是我的一个存储库:

public class StaffRepository : NHibernateRepository<IStaff>, 
{
    public IEnumerable<IStaff> GetBySiteRegionAndMonth(int siteId, int regionId, DateTime firstOfMonth)
    {
        return Repository.Where(ab => ab.SiteId == siteId && ab.WorkDate >= firstOfMonth && ab.WorkDate < firstOfMonth.AddMonths(1));
    }
}

基类:

    public class NHibernateRepository<TEntity> : IRepository<TEntity> where TEntity : IEntity
{
    protected ISession session;

    public NHibernateRepository()
    {
        this.session = new SessionCache().GetSession();
    }

    public IQueryable<TEntity> Query
    {
        get
        {
            return session.Query<TEntity>();
        }
    }

    // Add
    public void Add(TEntity entity)
    {
        session.Save(entity);
    }

    // GetById
    public TEntity GetById(int id)
    {
        // return session.Load<TEntity>(id);
        return this.Query.SingleOrDefault(e => e.Id == id);
    }
}

我现在尝试使用不会访问真实数据库的测试类来模拟基类NHibernateRepository,而是使用静态列表。这是我在结构图容器中注册测试类:

x.For(typeof(IRepository<>)).Use(typeof(TestNHibernateRepository<>));

我的问题是,真正的NHibernateRepository仍在测试中使用。我按照我的注册使用真实的StaffRepository

x.For<IStaffRepository>().Singleton().Use<StaffRepository>();

我所有其他测试类都注入正常,但我认为这是一个有问题的,因为它是一个继承的类。

如何确保我的StaffRepository使用TestNHibernateRepository代替NHibernateRepository

1 个答案:

答案 0 :(得分:3)

尽管创建虚假实现很容易,但是您的单元测试将非常不可靠,因为您的存储库暴露IQueryable<T>并导致tight coupling并且它将始终导致特定实现泄漏

这意味着如果在单元测试中使用IQueryable<T>上的LINQ to Objects实现,那么几乎所有通过IQueryable<T>编写的LINQ查询都将成功,而在使用时它们可能会失败NHibernate查询提供程序。

相反,您应该使用集成测试来测试依赖于IRepository<T>的类,这意味着您要与真实数据库进行通信,而不是内存中的替身。单元测试应该在不同的级别进行。

尽管IQueryable<T>是一个界面,但它并不是真正的抽象,或者至少它是Leaky Abstraction;一个Dependency Inversion Principle violation。因此,您应该确保IQueryable<T>仅在您的数据访问层中使用。

我发现的一个非常有效的解决方案是使用query handlers,其中查询对象(数据)是核心层的一部分,而他们的处理程序(使用O / RM) IQueryable<T>)的形式是数据访问层的一部分。您可以对这些处理程序进行集成测试,而这些处理程序的使用者可以再次进行单元测试。