【问题标题】:Configure OData Test Server配置 OData 测试服务器
【发布时间】:2021-03-31 17:10:04
【问题描述】:

尝试为我正在为 OdataQueryOptions 类编写的一些扩展设置单元/集成测试。我正在使用 .net 核心 3.1。

为了创建 SUT 实例 - 我需要一个 HttpRequest。我使用WebApplicationFactory创建的

public class TestingWebApplicationFactoryFixture : WebApplicationFactory<TestStartUp>
{
    protected override IHostBuilder CreateHostBuilder()
    {
        var builder = Host.CreateDefaultBuilder();
        builder.ConfigureWebHost(hostBuilder =>
        {
            hostBuilder.ConfigureServices(services =>
            {
                services.AddMvc(options => options.EnableEndpointRouting = false);
                services.AddOData();
            }).Configure(app =>
            {
                app.UseMvc(routeBuilder =>
                {
                    routeBuilder.EnableDependencyInjection();
                    routeBuilder.Select().Expand().OrderBy().Filter().MaxTop(int.MaxValue);
                });
            });
        });
        return builder;
    }

我安排测试使用TestServer 来生成HttpContext。然后使用 OdataQueryContext 和 HttpRequest 实例化 OdataQueryOptions 对象。

        const string path = "/?$filter=SalesOrderID eq 43659";
        var httpContext = await _testingWebApplicationFactoryFixture.Server.SendAsync(context => 
        {
            context.Request.Method = HttpMethods.Get;
            context.Request.Path = path;
        });
        var modelBuilder = new ODataConventionModelBuilder();
        modelBuilder.AddEntityType(typeof(Customer));
        var model = modelBuilder.GetEdmModel();
        var odataQueryContext = new ODataQueryContext(model, typeof(Customer), new ODataPath());
        var sut = new ODataQueryOptions<Customer>(odataQueryContext, httpContext.Request);

我在对象实例化过程中遇到异常:

System.ArgumentNullException
Value cannot be null. (Parameter 'provider')
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T] 
(IServiceProvider provider)
at Microsoft.AspNet.OData.Extensions.HttpRequestExtensions.CreateRequestScope(HttpRequest request, 
String routeName)
at Microsoft.AspNet.OData.Extensions.HttpRequestExtensions.CreateRequestContainer(HttpRequest 
request, String routeName)
at Microsoft.AspNet.OData.Extensions.HttpRequestExtensions.GetRequestContainer(HttpRequest request)
at Microsoft.AspNet.OData.Query.ODataQueryOptions..ctor(ODataQueryContext context, HttpRequest  
request)
at Microsoft.AspNet.OData.Query.ODataQueryOptions`1..ctor(ODataQueryContext context, HttpRequest 
request)

深入研究正在抛出的实际方法 - 这是因为 IServiceProvider 为空。这不应该由宿主处理吗?

更新:

我稍微修改了测试方法,以消除 WebApplicationFactory 类。

相反,我使用 IWebHostBuilder 创建了一个 TestServer:

    private IWebHostBuilder GetBuilder()
    {
        var webHostBuilder = new WebHostBuilder();
            webHostBuilder
                .UseTestServer()
                .ConfigureServices(services =>
                {
                    services.AddMvc(options => options.EnableEndpointRouting = false);
                    services.AddOData();
                }).Configure(app =>
                {
                    app.UseMvc(routeBuilder =>
                    {
                        routeBuilder.EnableDependencyInjection();
                        routeBuilder.Select().Expand().OrderBy().Filter().MaxTop(int.MaxValue);
                    });
                });
            return webHostBuilder;
    }

然后创建TestServer:

    [Fact]
    public async Task QueryGenerator_Generate_SomeExpress_ShouldProduce()
    {
        const string path = "/?$filter=SalesOrderID eq 43659";
        var testServer = new TestServer(GetBuilder());
        var httpContext = await testServer.SendAsync(context =>
        {
            context.Request.Method = HttpMethods.Get;
            context.Request.Path = path;
        });
        var modelBuilder = new ODataConventionModelBuilder();
        modelBuilder.AddEntityType(typeof(Customer));
        var model = modelBuilder.GetEdmModel();
        var odataQueryContext = new ODataQueryContext(model, typeof(Customer), new ODataPath());
        var sut = new ODataQueryOptions<Customer>(odataQueryContext, httpContext.Request);
    }

我得到了同样的例外。为什么 IServiceProvider 为空?

【问题讨论】:

  • 您找到解决方案了吗?
  • 有点。我放弃了使用 TestServer 的想法。相反,我创建了一个单独的 OdataQueryOptionFixture,它手动构造了 IServiceProvider。我会更新我的答案。

标签: asp.net-core odata testserver


【解决方案1】:

从未找到使用 TestServer 的解决方案,但我找到了解决方法。归根结底,我需要框架生成的 OdataQueryOptions 类。所以我在 Xunit 中创建了一个 IClassFixture 来手动创建它。

public class OdataQueryOptionFixture
{
    public IServiceProvider Provider { get; private set; }
    private IEdmModel _edmModel;

    public OdataQueryOptionFixture()
    {
        SetupFixture();
    }


    public ODataQueryOptions<T> CreateODataQueryOptions<T>(HttpRequest request)
        where T : class
    {
        var odataQueryContext = CreateOdataQueryContext<T>();
        var odataQueryOptions = new ODataQueryOptions<T>(odataQueryContext, request);
        return odataQueryOptions;
    }

    private ODataQueryContext CreateOdataQueryContext<T>()
        where T : class
    {
        var odataQueryContext = new ODataQueryContext(_edmModel, typeof(T), new ODataPath());
        return odataQueryContext;
    }

    private void SetupFixture()
    {
        var collection = new ServiceCollection();
        collection.AddOData();
        collection.AddTransient<ODataUriResolver>();
        collection.AddTransient<ODataQueryValidator>();
        Provider = collection.BuildServiceProvider();
        ConfigureRoutes();
        BuildModel();
    }

    private void ConfigureRoutes()
    {
        var routeBuilder = new RouteBuilder(Mock.Of<IApplicationBuilder>(x => x.ApplicationServices == Provider));
        routeBuilder.Select().Expand().OrderBy().Filter().MaxTop(int.MaxValue).Count();
        routeBuilder.EnableDependencyInjection();
    }
    private void BuildModel()
    {
        var edmContext = new AdventureWorksEdmContext();
        _edmModel = edmContext.BuildModel();
    }

在测试类中使用类fixture来构造OdataQueryOptions

        private QueryOptionsBuilder<Customer> GetSut(HttpRequest request)
    {
        var odataQueryOptions = _odataQueryOptionFixture.CreateODataQueryOptions<Customer>(request);
        var odataQuerySettings = new ODataQuerySettings();
        var odataValidationSettings = new ODataValidationSettings();
        var customerExpandBinder = new CustomerExpandBinder(odataValidationSettings, odataQueryOptions.SelectExpand);
        var customerOrderByBinder = new CustomerOrderByBinder(odataValidationSettings, odataQueryOptions.OrderBy);
        var customerSelectBinder = new CustomerSelectBinder(odataValidationSettings, odataQueryOptions.SelectExpand);
        var customerCompositeBinder = new CustomerCompositeBinder(customerExpandBinder, customerOrderByBinder, customerSelectBinder);
        return new QueryOptionsBuilder<Customer>(customerCompositeBinder, odataQuerySettings);
    }

TestServer 本来会更容易 - 但这可以完成工作。

【讨论】:

    猜你喜欢
    • 2021-03-21
    • 1970-01-01
    • 1970-01-01
    • 2017-06-18
    • 1970-01-01
    • 1970-01-01
    • 2013-09-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多