После большого количества разочарований этим у меня наконец-то есть решение, которым я доволен, по крайней мере, по части проблемы.
Сначала используйте интерфейс хранилища, например:
public interface IRepository
{
IQueryable<T> GetObjectSet<T>();
}
, который мы можем использовать для возврата либо коллекции в памяти, либо реальной коллекции с БД. Затем инкапсулируйте ваши запросы в объект запроса с интерфейсом, который выглядит примерно так:
public interface IQuery<T>
{
IQueryable<T> DoQuery(IQueryable<T> collection);
}
Теперь разделите свои юнит-тесты на 2 группы. Первая группа проверит правильность ваших запросов. сделать это так:
[TestMethod]
public void TestQueryFoo()
{
using(var repo = new SqlRepository("bogus connection string"))
{
var query = new FooQuery(); // implements IQuery<Foo>
var result = query.DoQuery(repo.GetObjectSet<Foo>()); // as long as we don't enumerate the IQueryable EF won't notice that the connection string is bogus
var sqlString = ((System.Data.Objects.ObjectQuery)query).ToTraceString(); // This will throw if the query can't be compiled to SQL
}
}
Второй набор модульных тестов может затем свободно тестировать вашу бизнес-логику, не беспокоясь о шаге компиляции SQL, который, безусловно, является самым сложным.
Это не идеально для любого уровня воображения, триггеры, очевидно, не будут запущены, ограничения, реализованные в БД, могут быть нарушены, и могут возникнуть некоторые проблемы с выходом из контекста и базы данных. Таким образом, хотя все еще необходимы сквозные интеграционные тесты, можно выявить, какая IMO является наиболее распространенной проблемой, возникающей во время выполнения, в простых модульных тестах.