简体   繁体   English

C#:在 OData 中手动创建过滤器选项

[英]C#: Manually Create Filter Options in OData

I am trying to manually create an OData query on service method.我正在尝试在服务方法上手动创建 OData 查询。

Need to create variable in ODataQueryOptions if possible.如果可能,需要在 ODataQueryOptions 中创建变量。 Filter requirement is on example,Description = "Furniture"过滤要求例如,Description = "Furniture"

http://localhost/odata/GetProductTypeDto()?$filter=Description eq 'Furniture'

Code:代码:

public async Task<ProductTypeDto> GetProductTypeDto(ODataQueryOptions<ProductTypeDto> odataQueryOptions)
{
    var dto = (IQueryable<ProductTypeDto>)odataQueryOptions.ApplyTo(_productRepository.GetProductTypes)();
    var dtoList = await dto.ToListAsync();
    return dto;
}

_productRepository.GetProductTypes() = // IQueryable which brings out this result {
  new ProductTypeDto {ProductTypeId = 1, Description = "Furniture"},
  new ProductTypeDto {ProductTypeId = 2, Description = "Electronics"},
  new ProductTypeDto {ProductTypeId = 3, Description = "Books"}
}

We are now trying to to create filter Furniture in variable odataQueryOptions, without using API.我们现在尝试在变量 odataQueryOptions 中创建过滤器 Furniture,而不使用 API。

Trying to unit test something later,稍后尝试对某些内容进行单元测试,

var actualResult = product.GetProductTypeDto(odataQueryOptions)
Assert.Equals(actualResult.ProductTypeId, 1);
Assert.Equals(actualResult.Description, "Furniture");

update更新

One of the reasons that it's hard to find specific guidance in this area for OData, is that the URL resolution and OData Deserialization (especially around Patch ) is managed for us, or abstracted away.在这方面很难找到 OData 的具体指南的原因之一是 URL 解析和 OData 反序列化(尤其是在Patch周围)是为我们管理的,或者被抽象掉了。 This is good and bad, but it means traditional API endpoint testing in isolation becomes complicated.这有好有坏,但这意味着孤立的传统 API 端点测试变得复杂。

For instance a traditional API endpoint will have discrete input arguments and a discrete response argument, however OData arguments are generally wrapped inside generic dictionaries or helper objects that know how to manipulate queries based on their input but are hard to manually inspect.例如,传统的 API 端点将具有离散的输入参数和离散的响应参数,但是 OData 参数通常包装在通用字典或帮助器对象中,它们知道如何根据输入操作查询但很难手动检查。 The response from an endpoint is also usually wrapped in a generic negotiated content response wrapper来自端点的响应通常也包装在通用协商内容响应包装器中

Units tests should focus on behaviour only 单元测试应该只关注行为

Unit testing involves testing a part of an application in isolation from its infrastructure and dependencies.单元测试涉及独立于其基础设施和依赖项测试应用程序的一部分。 When you unit test controller logic, only the content of a single action or method is tested, not the behavior of its dependencies or of the framework itself.当您对控制器逻辑进行单元测试时,只测试单个操作或方法的内容,而不是其依赖项或框架本身的行为。 Unit tests do not detect issues in the interaction between components — that is the purpose of integration testing.单元测试不检测组件之间交互中的问题——这是集成测试的目的

In the case of OData, query options like $filter , $select , $expand ... are really part of the framework, as is content negotiation and serialization.在 OData 的情况下,像$filter$select$expand ... 这样的查询选项实际上是框架的一部分,内容协商和序列化也是如此。 These elements require a lot of effort and configuration to mock for the purposes of a traditional unit test, so much so that many tests become indeterminate, when they pass or fail, is this related to the configuration or that actual logic that you were trying to target?为了传统单元测试的目的,这些元素需要大量的努力和配置来模拟,以至于许多测试变得不确定,当它们通过或失败时,这是否与配置或您试图尝试的实际逻辑有关目标?

OData endpoints on the controller are generally easier to test using integration testing practises.控制器上的 OData 端点通常更容易使用集成测试实践进行测试 Specifically for OData this means that you must run an instance of the actual service (either in memory, or deployed locally or to a specific test environment) so you can evaluate endpoints and how they evaluate query epressions through the HTTP pipeline.特别是对于 OData,这意味着您必须运行实际服务的实例(在内存中,或在本地部署或在特定测试环境中),以便您可以评估端点以及它们如何通过 HTTP 管道评估查询表达。

You can automate this in VS, or do it in two steps, deploy your API to a testing location with a prepared database and then execute test scripts against it, either as VS unit tests or using external tools like Postman .您可以在 VS 中自动执行此操作,或分两步完成,将 API 部署到带有准备好的数据库的测试位置,然后针对它执行测试脚本,作为 VS 单元测试或使用Postman等外部工具。

  • There are NuGet packages that can help this process, but it is possible to " self host " your API programatically, so you can hook this up in the unit test init process.有 NuGet 包可以帮助这个过程,但是可以以编程方式“自托管”你的 API,所以你可以在单元测试 init 过程中连接它。


These reasons complicate unit tests against OData endpoint methods directly:这些原因直接使针对 OData 端点方法的单元测试复杂化:

  • Much of the projection logic ($select/$expand) is evaluated by the EnableQueryAttribute许多投影逻辑 ($select/$expand) 由EnableQueryAttribute评估
  • To construct an instance of ODataQueryOptions requires that the EdmModel is constructed and passed in as well as the Http request to operate on.要构造ODataQueryOptions的实例,需要构造并传入EdmModel以及要对其进行操作的 Http 请求。

So the amount of effort required to setup your mocked QueryOptions is almost the same effort to just run an instance of the service.因此,设置模拟 QueryOptions所需的工作量几乎与仅运行服务实例所需的工作量相同。

If your test routine requires specific and complex manual configuration that basically recreates the API environment almost in full, then there is a high risk of false test results (positivites and negatives) when a test fails, does that mean that the setup for the test was faulty or that the production code you are testing is at fault?如果您的测试例程需要特定且复杂的手动配置,基本上几乎完整地重新创建 API 环境,那么当测试失败时存在错误测试结果(正面和负面)的高风险,这是否意味着测试的设置是有问题还是您正在测试的生产代码有问题?

Some people have had success in this area, have a look at this post in the OData Project forum: [feature/netcore] How to unit test with ODataQueryOptions #1352有些人在这方面取得了成功,请查看 OData 项目论坛中的这篇文章: [feature/netcore] 如何使用 ODataQueryOptions 进行单元测试 #1352

Also have a look at this guidance, though it is less specific to your needs:另请查看此指南,尽管它不太适合您的需求:
Unit test controller logic in ASP.NET Core ASP.NET Core 中的单元测试控制器逻辑

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM