I am using NHibernate and have many repositories, which all inherit from a base NHibernateRepository class. Here is one of my repositories:
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));
}
}
And the base class:
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);
}
}
I am now trying to mock to the base class NHibernateRepository
using a test class that won't access a real database, but will instead use a static list. Here is my registration of the test class in my structure map container:
x.For(typeof(IRepository<>)).Use(typeof(TestNHibernateRepository<>));
My problem is, that the real NHibernateRepository
is still used in the tests. I am using the real StaffRepository
as per my registration:
x.For<IStaffRepository>().Singleton().Use<StaffRepository>();
All my other test classes are injected fine, but I think this is being problematic as it is an inherited class.
How can I make sure that my StaffRepository uses the TestNHibernateRepository
instead of NHibernateRepository
?
Although it would be easy to create a fake implementation, your unit tests will be very unreliable, because your repository exposes IQueryable<T>
and that causes tight coupling and it will always cause the specific implementation to leak through.
This means that if you use an LINQ to Objects implementation over IQueryable<T>
in your unit tests, almost all LINQ queries that you write over IQueryable<T>
will always succeed, while they might very well fail when using the NHibernate query provider.
Instead, you should test classes that depend on IRepository<T>
using integration testing, which means you communicate with the real database, not an in-memory stand-in. Unit testing should be done at a different level.
Even though IQueryable<T>
is an interface, it's not really an abstraction, or at least, it's a Leaky Abstraction; a Dependency Inversion Principle violation. So instead, you should ensure that IQueryable<T>
is only used within your Data Access Layer.
A very effective solution I found to this, is the use of query handlers, where the query objects (the data) is part of a core layer, while their handlers (that make use of an O/RM in the form of IQueryable<T>
) are part of the Data Access Layer. You integration test those handlers, while consumers of those handlers, can again be unit tested.