【问题标题】:How to mock a base class using structure map?如何使用结构映射模拟基类?
【发布时间】:2017-08-10 09:04:06
【问题描述】:

我正在使用 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

【问题讨论】:

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


    【解决方案1】:

    虽然创建假实现很容易,但您的单元测试将非常不可靠,因为您的存储库暴露了IQueryable&lt;T&gt;,这会导致tight coupling,它总是会导致特定的实现泄漏。

    这意味着,如果您在单元测试中通过IQueryable&lt;T&gt; 使用 LINQ to Objects 实现,则几乎所有通过IQueryable&lt;T&gt; 编写的 LINQ 查询都将始终成功,而在使用 NHibernate 查询提供程序时它们很可能会失败.

    相反,您应该使用集成测试来测试依赖于IRepository&lt;T&gt; 的类,这意味着您与真实 数据库进行通信,而不是与内存中的替身进行通信。单元测试应该在不同的层次上进行。

    尽管IQueryable&lt;T&gt; 是一个接口,但它并不是真正的抽象,或者至少,它是一个Leaky AbstractionDependency Inversion Principle violation。因此,您应该确保 IQueryable&lt;T&gt; 仅在您的数据访问层中使用。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多