The following line fails with a null reference, when testing:
var awards = _session.QueryOver().Where(x => x.BusinessId == (int)business).List
This is not a good idea. You should not mock the types you don't own. Instead you should introduce a Repository, base its interface on domain/business language and implement it using NHibernate. Implementation can use ICriteria, HQL, QueryOver, Linq etc. The point is that this decision will be encapsulated and hidden from the code that consumes repository.
You can write an integration test that will test combination of your interface + Real ORM + Real or Fake database. Please take a look at this and this answers about testing repositories and data access. Testing the code that uses Repository is also super easy because you can mock Repository interface.
What are the advantages of this approach other than testability? They are somewhat related to each other:
I've used several approaches in the past. One way is, as others have suggested, to create a Repository class that you can mock/stub that encapsulates your queries. One problem with this is that it's not very flexible and you wind up having a stored procedure like solution, except this one is in code rather than the database.
A recent solution I have tried is creating a QueryOver stub that I provide when I stub the QueryOver method. I can then provide a list of items that should be returned. Keep in mind if you using this approach you should not only write unit tests, but an integration test, which will test whether or not the query actually works.
public class QueryOverStub<TRoot, TSub> : IQueryOver<TRoot, TSub>
{
private readonly TRoot _singleOrDefault;
private readonly IList<TRoot> _list;
private readonly ICriteria _root = MockRepository.GenerateStub<ICriteria>();
public QueryOverStub(IList<TRoot> list)
{
_list = list;
}
public QueryOverStub(TRoot singleOrDefault)
{
_singleOrDefault = singleOrDefault;
}
public ICriteria UnderlyingCriteria
{
get { return _root; }
}
public ICriteria RootCriteria
{
get { return _root; }
}
public IList<TRoot> List()
{
return _list;
}
public IList<U> List<U>()
{
throw new NotImplementedException();
}
public IQueryOver<TRoot, TRoot> ToRowCountQuery()
{
throw new NotImplementedException();
}
public IQueryOver<TRoot, TRoot> ToRowCountInt64Query()
{
throw new NotImplementedException();
}
public int RowCount()
{
return _list.Count;
}
public long RowCountInt64()
{
throw new NotImplementedException();
}
public TRoot SingleOrDefault()
{
return _singleOrDefault;
}
public U SingleOrDefault<U>()
{
throw new NotImplementedException();
}
public IEnumerable<TRoot> Future()
{
return _list;
}
public IEnumerable<U> Future<U>()
{
throw new NotImplementedException();
}
public IFutureValue<TRoot> FutureValue()
{
throw new NotImplementedException();
}
public IFutureValue<U> FutureValue<U>()
{
throw new NotImplementedException();
}
public IQueryOver<TRoot, TRoot> Clone()
{
throw new NotImplementedException();
}
public IQueryOver<TRoot> ClearOrders()
{
return this;
}
public IQueryOver<TRoot> Skip(int firstResult)
{
return this;
}
public IQueryOver<TRoot> Take(int maxResults)
{
return this;
}
public IQueryOver<TRoot> Cacheable()
{
return this;
}
public IQueryOver<TRoot> CacheMode(CacheMode cacheMode)
{
return this;
}
public IQueryOver<TRoot> CacheRegion(string cacheRegion)
{
return this;
}
public IQueryOver<TRoot, TSub> And(Expression<Func<TSub, bool>> expression)
{
return this;
}
public IQueryOver<TRoot, TSub> And(Expression<Func<bool>> expression)
{
return this;
}
public IQueryOver<TRoot, TSub> And(ICriterion expression)
{
return this;
}
public IQueryOver<TRoot, TSub> AndNot(Expression<Func<TSub, bool>> expression)
{
return this;
}
public IQueryOver<TRoot, TSub> AndNot(Expression<Func<bool>> expression)
{
return this;
}
public IQueryOverRestrictionBuilder<TRoot, TSub> AndRestrictionOn(Expression<Func<TSub, object>> expression)
{
throw new NotImplementedException();
}
public IQueryOverRestrictionBuilder<TRoot, TSub> AndRestrictionOn(Expression<Func<object>> expression)
{
throw new NotImplementedException();
}
public IQueryOver<TRoot, TSub> Where(Expression<Func<TSub, bool>> expression)
{
return this;
}
public IQueryOver<TRoot, TSub> Where(Expression<Func<bool>> expression)
{
return this;
}
public IQueryOver<TRoot, TSub> Where(ICriterion expression)
{
return this;
}
public IQueryOver<TRoot, TSub> WhereNot(Expression<Func<TSub, bool>> expression)
{
return this;
}
public IQueryOver<TRoot, TSub> WhereNot(Expression<Func<bool>> expression)
{
return this;
}
public IQueryOverRestrictionBuilder<TRoot, TSub> WhereRestrictionOn(Expression<Func<TSub, object>> expression)
{
return new IQueryOverRestrictionBuilder<TRoot, TSub>(this, "prop");
}
public IQueryOverRestrictionBuilder<TRoot, TSub> WhereRestrictionOn(Expression<Func<object>> expression)
{
return new IQueryOverRestrictionBuilder<TRoot, TSub>(this, "prop");
}
public IQueryOver<TRoot, TSub> Select(params Expression<Func<TRoot, object>>[] projections)
{
return this;
}
public IQueryOver<TRoot, TSub> Select(params IProjection[] projections)
{
return this;
}
public IQueryOver<TRoot, TSub> SelectList(Func<QueryOverProjectionBuilder<TRoot>, QueryOverProjectionBuilder<TRoot>> list)
{
return this;
}
public IQueryOverOrderBuilder<TRoot, TSub> OrderBy(Expression<Func<TSub, object>> path)
{
return new IQueryOverOrderBuilder<TRoot, TSub>(this, path);
}
public IQueryOverOrderBuilder<TRoot, TSub> OrderBy(Expression<Func<object>> path)
{
return new IQueryOverOrderBuilder<TRoot, TSub>(this, path, false);
}
public IQueryOverOrderBuilder<TRoot, TSub> OrderBy(IProjection projection)
{
return new IQueryOverOrderBuilder<TRoot, TSub>(this, projection);
}
public IQueryOverOrderBuilder<TRoot, TSub> OrderByAlias(Expression<Func<object>> path)
{
return new IQueryOverOrderBuilder<TRoot, TSub>(this, path, true);
}
public IQueryOverOrderBuilder<TRoot, TSub> ThenBy(Expression<Func<TSub, object>> path)
{
return new IQueryOverOrderBuilder<TRoot, TSub>(this, path);
}
public IQueryOverOrderBuilder<TRoot, TSub> ThenBy(Expression<Func<object>> path)
{
return new IQueryOverOrderBuilder<TRoot, TSub>(this, path, false);
}
public IQueryOverOrderBuilder<TRoot, TSub> ThenBy(IProjection projection)
{
return new IQueryOverOrderBuilder<TRoot, TSub>(this, projection);
}
public IQueryOverOrderBuilder<TRoot, TSub> ThenByAlias(Expression<Func<object>> path)
{
return new IQueryOverOrderBuilder<TRoot, TSub>(this, path, true);
}
public IQueryOver<TRoot, TSub> TransformUsing(IResultTransformer resultTransformer)
{
return this;
}
public IQueryOverFetchBuilder<TRoot, TSub> Fetch(Expression<Func<TRoot, object>> path)
{
return new IQueryOverFetchBuilder<TRoot, TSub>(this, path);
}
public IQueryOverLockBuilder<TRoot, TSub> Lock()
{
throw new NotImplementedException();
}
public IQueryOverLockBuilder<TRoot, TSub> Lock(Expression<Func<object>> alias)
{
throw new NotImplementedException();
}
public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<TSub, U>> path)
{
return new QueryOverStub<TRoot, U>(new List<TRoot>());
}
public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<U>> path)
{
return new QueryOverStub<TRoot, U>(new List<TRoot>());
}
public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<TSub, U>> path, Expression<Func<U>> alias)
{
return new QueryOverStub<TRoot, U>(_list);
}
public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias)
{
return new QueryOverStub<TRoot, U>(new List<TRoot>());
}
public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<TSub, U>> path, JoinType joinType)
{
return new QueryOverStub<TRoot, U>(new List<TRoot>());
}
public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<U>> path, JoinType joinType)
{
return new QueryOverStub<TRoot, U>(new List<TRoot>());
}
public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<TSub, U>> path, Expression<Func<U>> alias, JoinType joinType)
{
return new QueryOverStub<TRoot, U>(new List<TRoot>());
}
public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<U>> path, Expression<Func<U>> alias, JoinType joinType)
{
return new QueryOverStub<TRoot, U>(new List<TRoot>());
}
public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<TSub, IEnumerable<U>>> path)
{
return new QueryOverStub<TRoot, U>(new List<TRoot>());
}
public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path)
{
return new QueryOverStub<TRoot, U>(new List<TRoot>());
}
public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<TSub, IEnumerable<U>>> path, Expression<Func<U>> alias)
{
return new QueryOverStub<TRoot, U>(new List<TRoot>());
}
public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias)
{
return new QueryOverStub<TRoot, U>(new List<TRoot>());
}
public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<TSub, IEnumerable<U>>> path, JoinType joinType)
{
return new QueryOverStub<TRoot, U>(new List<TRoot>());
}
public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, JoinType joinType)
{
return new QueryOverStub<TRoot, U>(new List<TRoot>());
}
public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<TSub, IEnumerable<U>>> path, Expression<Func<U>> alias, JoinType joinType)
{
return new QueryOverStub<TRoot, U>(new List<TRoot>());
}
public IQueryOver<TRoot, U> JoinQueryOver<U>(Expression<Func<IEnumerable<U>>> path, Expression<Func<U>> alias, JoinType joinType)
{
return new QueryOverStub<TRoot, U>(new List<TRoot>());
}
public IQueryOver<TRoot, TSub> JoinAlias(Expression<Func<TSub, object>> path, Expression<Func<object>> alias)
{
return this;
}
public IQueryOver<TRoot, TSub> JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias)
{
return this;
}
public IQueryOver<TRoot, TSub> JoinAlias(Expression<Func<TSub, object>> path, Expression<Func<object>> alias, JoinType joinType)
{
return this;
}
public IQueryOver<TRoot, TSub> JoinAlias(Expression<Func<object>> path, Expression<Func<object>> alias, JoinType joinType)
{
return this;
}
public IQueryOverSubqueryBuilder<TRoot, TSub> WithSubquery
{
get { return new IQueryOverSubqueryBuilder<TRoot, TSub>(this); }
}
public IQueryOverJoinBuilder<TRoot, TSub> Inner
{
get { return new IQueryOverJoinBuilder<TRoot, TSub>(this, JoinType.InnerJoin); }
}
public IQueryOverJoinBuilder<TRoot, TSub> Left
{
get { return new IQueryOverJoinBuilder<TRoot, TSub>(this, JoinType.LeftOuterJoin); }
}
public IQueryOverJoinBuilder<TRoot, TSub> Right
{
get { return new IQueryOverJoinBuilder<TRoot, TSub>(this, JoinType.RightOuterJoin); }
}
public IQueryOverJoinBuilder<TRoot, TSub> Full
{
get { return new IQueryOverJoinBuilder<TRoot, TSub>(this, JoinType.FullJoin); }
}
}
Lately I've been moving the code that calls .QueryOver() to a protected virtual method instead and building my own TestableXYZ that inherits from XYZ and overrides the method and returns a empty list or whatever. This way I dont need a repository just for testing.
Don't try to mock QueryOver. Instead, define a repository interface (which uses QueryOver internally) and mock that interface.
I don't think the above code is right. AFAIK QueryOver is an extension method on ISession interface and you can not Mock extensions method like that (at least not with conventional Mocking tools like Moq or RhinoMocks).