LINQ to Entities错误发生在运行时,但不在单元测试中
本文关键字:单元测试 运行时 LINQ Entities 错误 to | 更新日期: 2023-09-27 18:25:51
我正在我的一个控制器中对一个方法进行单元测试,以检查是否使用Linq查询返回了正确的数据(这可能是一个集成测试,但问题仍然存在)。
我试图尽可能多地遵循TTD,在代码中修复之前,复制我在测试运行时遇到的任何错误。
但是,我遇到了一个错误,该错误只发生在应用程序运行时执行期间,而不是在测试期间。
我在运行时遇到的异常是:
引发异常:Newtonsoft.Json.dll 中的"System.NotSupportedException"
其他信息:LINQ to Entities无法识别方法"System.String ToLowerInvariant()"方法,并且此方法无法转换为存储表达式。
测试方法为:
[HttpGet]
public ActionResult GetRegions(string term)
{
var regions = from region in DbContext.Culture
where
!region.NeutralCultureFlag &&
(term == null || (region.NativeName + region.CultureCode).ToLowerInvariant().Contains(term.ToLowerInvariant()))
orderby region.Name
select region;
return Json(regions.Select(x => new
{
id = x.CultureId,
text = x.NativeName + " (" + x.CultureCode + ")"
})
);
}
错误的修复方法显然是将(region.NativeName + region.CultureCode).ToLowerInvariant()
更改为(region.NativeName.ToLowerInvariant() + region.CultureCode.ToLowerInvariant())
,但我希望在修复之前在测试中得到这个错误。
我的测试方法是:
public void Test1(string term, int expectedCount)
{
var result = _controller.GetRegions(term);
Assert.IsType(typeof (JsonNetResult), result);
var jsonResult = (JsonNetResult)result;
var data = GetJsonObject<List<JsonData>>(jsonResult);
}
JsonNetResult
是一个自定义类,它扩展了普通的JsonResult
,因此我可以使用Json.Net而不是标准的Json serializer。
JsonNetResult
中的ExecuteResult
方法看起来像:
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = string.IsNullOrEmpty(this.ContentType) ? "application/json" : this.ContentType;
if (this.ContentEncoding != null)
response.ContentEncoding = this.ContentEncoding;
if (this.Data == null)
return;
var scriptSerializer = JsonSerializer.Create(this.Settings);
using (var sw = new StringWriter())
{
scriptSerializer.Serialize(sw, this.Data); //error occurs here
response.Write(sw.ToString());
}
}
异常发生在scriptSerializer.Serialize(sw, this.Data);
。
有没有一种方法可以在我的单元测试中复制错误,这样我就可以确保它按照TTD原则正确修复?
因为您的单元测试使用模拟上下文,所以您得到的是对象的LINQ,而不是实体的LINQ。
linq到实体vs linq到对象-它们是一样的吗?
来自以上链接:
LINQ to Objects是IEnumerable上的一组扩展方法允许您对任意序列执行内存中的查询操作的对象。必要时,这些方法接受简单委托。
LINQ to Entities是一个具有一组扩展的LINQ提供程序IQueryable上的方法。这些方法建立了一个表达式树(这就是代理实际作为表达式<>s传递的原因),并且提供者将基于其对SQL查询的解析来构建SQL查询表达式树。
例如,考虑以下查询:
var query1 = mydb.MyEntity.Select(x => x.SomeProp).Where(x => x ==> "Prop"); var query2 = mydb.MyEntity.Select(x =>> x.SomeProp).AsEnumerable().Where(x => x == "Prop");
第一个查询是将建立一个由select和where组成的表达式树,两个Lambda实际上被认为是LambdaExpressions。这个LINQ to Entities提供程序将其转换为SQL选择和筛选。
第二个查询插入一个AsEnumerable(),它将强制查询的剩余部分使用LINQ to Objects。在这种情况下提供程序将仅基于所选内容生成SQL,并返回所有数据库中的那些记录,然后将进行筛选在内存中。显然,这可能会慢得多。