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 to Entities错误发生在运行时,但不在单元测试中

因为您的单元测试使用模拟上下文,所以您得到的是对象的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,并返回所有数据库中的那些记录,然后将进行筛选在内存中。显然,这可能会慢得多。