Вы не можете - если модульное тестирование означает, что вы используете в памяти поддельный репозиторий и, следовательно, используете LINQ to Objects. Если вы тестировали свои запросы с помощью LINQ to Objects, вы тестировали не ваше приложение, а только свой поддельный репозиторий.
Ваше исключение - менее опасный случай, поскольку оно указывает на то, что у вас есть красный тест, но, вероятно, на самом деле работающее приложение.
С другой стороны, более опасно, если у вас есть зеленый тест, но вылетает приложение или запросы, которые не возвращают те же результаты, что и ваш тест. Запросы типа ...
context.MyEntities.Where(e => MyBoolFunction(e)).ToList()
или
context.MyEntities.Select(e => new MyEntity { Name = e.Name }).ToList()
... будет отлично работать в вашем тесте, но не с LINQ to Entities в вашем приложении.
запрос типа ...
context.MyEntities.Where(e => e.Name == "abc").ToList()
... потенциально вернет результаты, отличные от LINQ для объектов, чем LINQ для объектов.
Вы можете проверить это и запрос в своем вопросе, только создав интеграционные тесты, использующие поставщика приложения LINQ to Entities и реальную базу данных.
Редактировать
Если вы все еще хотите написать модульные тесты, я думаю, что вы должны подделать сам запрос или хотя бы выражения в запросе. Я мог предположить, что что-то вроде следующего кода может работать:
Создать интерфейс для выражения Where
:
public interface IEntityExpressions
{
Expression<Func<MyEntity, bool>> GetSearchByDateExpression(DateTime date);
// maybe more expressions which use EntityFunctions or SqlFunctions
}
Создание реализации для вашего приложения ...
public class EntityExpressions : IEntityExpressions
{
public Expression<Func<MyEntity, bool>>
GetSearchByDateExpression(DateTime date)
{
return e => EntityFunctions.TruncateTime(e.Date) == date;
// Expression for LINQ to Entities, does not work with LINQ to Objects
}
}
... и вторая реализация в вашем модульном тестовом проекте:
public class FakeEntityExpressions : IEntityExpressions
{
public Expression<Func<MyEntity, bool>>
GetSearchByDateExpression(DateTime date)
{
return e => e.Date.Date == date;
// Expression for LINQ to Objects, does not work with LINQ to Entities
}
}
В вашем классе, где вы используете запрос, создайте закрытый член этого интерфейса и два конструктора:
public class MyClass
{
private readonly IEntityExpressions _entityExpressions;
public MyClass()
{
_entityExpressions = new EntityExpressions(); // "poor man's IOC"
}
public MyClass(IEntityExpressions entityExpressions)
{
_entityExpressions = entityExpressions;
}
// just an example, I don't know how exactly the context of your query is
public IQueryable<MyEntity> BuildQuery(IQueryable<MyEntity> query,
SearchOptions searchOptions)
{
if (searchOptions.Date.HasValue)
query = query.Where(_entityExpressions.GetSearchByDateExpression(
searchOptions.Date));
return query;
}
}
Используйте первый (по умолчанию) конструктор в вашем приложении:
var myClass = new MyClass();
var searchOptions = new SearchOptions { Date = DateTime.Now.Date };
var query = myClass.BuildQuery(context.MyEntities, searchOptions);
var result = query.ToList(); // this is LINQ to Entities, queries database
Используйте второй конструктор с FakeEntityExpressions
в своем модульном тесте:
IEntityExpressions entityExpressions = new FakeEntityExpressions();
var myClass = new MyClass(entityExpressions);
var searchOptions = new SearchOptions { Date = DateTime.Now.Date };
var fakeList = new List<MyEntity> { new MyEntity { ... }, ... };
var query = myClass.BuildQuery(fakeList.AsQueryable(), searchOptions);
var result = query.ToList(); // this is LINQ to Objects, queries in memory
Если вы используете контейнер для внедрения зависимостей, вы можете использовать его, вставив соответствующую реализацию, если IEntityExpressions
, в конструктор и не нужен конструктор по умолчанию.
Я тестировал приведенный выше пример кода, и он работал.