gpt4 book ai didi

entity-framework - EntityFunctions.TruncateTime 和单元测试

转载 作者:行者123 更新时间:2023-12-03 09:23:11 28 4
gpt4 key购买 nike

我正在使用 System.Data.Objects.EntityFunctions.TruncateTime在我的查询中获取日期时间的日期部分的方法:

if (searchOptions.Date.HasValue)
query = query.Where(c =>
EntityFunctions.TruncateTime(c.Date) == searchOptions.Date);

此方法(我相信这同样适用于其他 EntityFunctions 方法)不能在 LINQ to Entities 之外执行。在单元测试中执行此代码(实际上是 LINQ to objects)会导致 NotSupportedException被抛出:

System.NotSupportedException : This function can only be invoked from LINQ to Entities.



我正在使用带有假 DbSets 的存储库的 stub 在我的测试中。

那么我应该如何对我的查询进行单元测试呢?

最佳答案

你不能 - 如果单元测试意味着你在内存中使用了一个假的存储库,因此你正在使用 LINQ to Objects。如果您使用 LINQ to Objects 测试您的查询,您并没有测试您的应用程序,而只是测试了您的假存储库。

您的异常(exception)是不太危险的情况,因为它表明您有一个红色测试,但实际上可能是一个工作应用程序。

更危险的是相反的情况:进行绿色测试但应用程序崩溃或查询返回的结果与您的测试不同。查询如...

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 to Objects 可能会返回与 LINQ to Entities 不同的结果。

您只能通过构建使用应用程序的 LINQ to Entities 提供程序和真实数据库的集成测试来测试这个和您的问题中的查询。

编辑

如果您仍想编写单元测试,我认为您必须伪造查询本身或至少伪造查询中的表达式。我可以想象以下代码行中的某些内容可能会起作用:

Where 创建一个接口(interface)表达:
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
}
}

在您使用查询的类中,创建此接口(interface)的私有(private)成员和两个构造函数:
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

如果您使用的是依赖注入(inject)容器,则可以通过注入(inject)适当的实现来利用它,如果 IEntityExpressions进入构造函数,不需要默认构造函数。

我已经测试了上面的示例代码并且它有效。

关于entity-framework - EntityFunctions.TruncateTime 和单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9585203/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com