【问题标题】:WebApplicationFactory throws error that contentRootPath does not exist in ASP.NET Core integration testWebApplicationFactory 在 ASP.NET Core 集成测试中抛出 contentRootPath 不存在的错误
【发布时间】:2018-11-12 20:44:32
【问题描述】:

我有一个 ASP.NET Core 项目,其中包含一些简单的 Razor 页面和一个 Web API 控制器。

我使用Clean Architecture 作为起点。我重命名了项目名称,删除了 MVC 内容并添加了一些我自己的代码。一切运行正常。

但是,集成测试在调用factory.CreateClient() 时会抛出以下错误:

Test Name:  ToDo.Tests.Integration.Web.HomeControllerIndexShould.ReturnViewWithCorrectMessage
Test FullName:  ToDo.Tests.Integration.Web.HomeControllerIndexShould.ReturnViewWithCorrectMessage
Test Source:    C:\Source\Utopia\tests\ToDo.Tests\Integration\Web\HomeControllerIndexShould.cs : line 18
Test Outcome:   Failed
Test Duration:  0:00:00,001

Result StackTrace:  
at Microsoft.AspNetCore.Hosting.Internal.HostingEnvironmentExtensions.Initialize(IHostingEnvironment hostingEnvironment, String contentRootPath, WebHostOptions options)
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.BuildCommonServices(AggregateException& hostingStartupErrors)
   at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
   at Microsoft.AspNetCore.TestHost.TestServer..ctor(IWebHostBuilder builder, IFeatureCollection featureCollection)
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.CreateServer(IWebHostBuilder builder)
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.EnsureServer()
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.CreateDefaultClient(DelegatingHandler[] handlers)
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.CreateClient(WebApplicationFactoryClientOptions options)
   at ToDo.Tests.Integration.Web.HomeControllerIndexShould..ctor(CustomWebApplicationFactory`1 factory) in C:\Source\Utopia\tests\ToDo.Tests\Integration\Web\HomeControllerIndexShould.cs:line 14
Result Message: 
System.ArgumentException : The content root 'C:\Source\Utopia\ToDo.Web' does not exist.
Parameter name: contentRootPath

我尝试使用builder.UseContentRootbuilder.UseSolutionRelativeContentRoot 配置自定义WebApplicationFactory,但无论我对ContentRoot 方法使用什么值,它都会抛出相同的错误。

我不知道为什么我的测试失败,而 Clean Architecture 示例中的测试正在运行。我也不知道怎么解决。

任何指针都非常感谢!

【问题讨论】:

  • 不知何故,我只是自己在项目中遇到了这个问题。我将接受的答案的解决方案添加到 CleanArchitecture 的 3.1 更新中,它似乎已经修复了它。
  • @ssmith 我确实想知道是什么引发了这个问题......不知何故,您的 2.2 Clean Architecture 和 3.1/我的代码之间发生了一些变化。
  • 如果你以后遇到问题,也请在 repo 上提出问题!谢谢!
  • 当我尝试将测试项目从一个解决方案复制到另一个解决方案时,这发生在我身上。我的测试项目名称中的命名空间,它包含目录、代码文件,到处都必须完美对齐。

标签: c# asp.net-core integration-testing


【解决方案1】:

这个方法对我有用

        var client = _factory
            .WithWebHostBuilder(builder => builder.UseSolutionRelativeContentRoot("relative/path/of/project/under/test"))
            .CreateClient();

How the test infrastructure infers the app content root path 说(添加了我的标记)

WebApplicationFactory 构造函数通过在包含集成测试的程序集上搜索 WebApplicationFactoryContentRootAttribute 来推断应用内容根路径,其中的键等于 TEntryPoint 程序集 System.Reflection.Assembly.FullName。如果未找到具有正确键的属性,WebApplicationFactory 将返回搜索解决方案文件 (.sln) 并将 TEntryPoint 程序集名称附加到解决方案目录。应用根目录(内容根路径)用于发现视图和内容文件。

【讨论】:

    【解决方案2】:

    我对这个问题的解决方案是使用 Application Startup 定义 WebApplicationFactory,但使用 TestStartup 设置 WebHostBuilder

    例子:

    public class MyApplicationFactory : WebApplicationFactory<Startup>
    {
        protected override IWebHostBuilder CreateWebHostBuilder()
        {
            return WebHost.CreateDefaultBuilder();
        }
    
        protected override void ConfigureWebHost(IWebHostBuilder builder)
        {
            builder.UseStartup<TestStartup>();
    
            base.ConfigureWebHost(builder);
        }
    }
    

    【讨论】:

      【解决方案3】:

      看来WebApplicationFactory应该使用真正的Startup类作为参数类型:

      class TestWebApplicationFactory : WebApplicationFactory<Startup>
      {
           protected override IWebHostBuilder CreateWebHostBuilder()
           {
               return WebHost.CreateDefaultBuilder<TestableStartup>();
           }
      }
      

      请注意,Startup 是真正 SUT 代码上的类型,而 TestableStartup 是 TestingStartup 配置。

      【讨论】:

        【解决方案4】:

        如果您使用的是 ReSharper,它很可能与版本有关。我们发现版本 2018.3 存在问题。添加 UseSolutionRelativeContentRoot 解决了它。

            protected override void ConfigureWebHost(IWebHostBuilder builder)
            {
                    builder.UseKestrel()
                    .UseSolutionRelativeContentRoot("")
                    .ConfigureAppConfiguration((context, configBuilder) =>
                    {
                      // Config code
                    })
                    .UseStartup<Startup>();
            }
        

        【讨论】:

        • 这对我来说是解决方案,因为项目不在根目录中
        【解决方案5】:

        我不完全确定你在说什么,但首先你不应该在测试项目中配置这样的东西。相反,您应该创建一个类似TestStartup 的类并从SUT 的Startup 类继承。在 SUT 的 Startup 类中,您应该将诸如 DB 设置之类的东西分解到虚拟私有方法中,然后您可以覆盖 TestStartup。例如,您可以创建如下方法:

        private virtual void ConfigureDatabase(IServiceCollection services)
        {
            services.AddDbContext<MyContext>(o =>
                o.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        }
        

        然后在您的 TestStartup 中,您将添加类似以下内容:

        private override void ConfigureDatabase(IServiceCollection services)
        {
            var databaseName = Guid.NewGuid().ToString();
            services.AddDbContext<MyContext>(o =>
                o.UseInMemoryDatabase(databaseName));
        }
        

        然后,在设置你的工厂进行测试时,你告诉它使用你的TestStartup

        var client = factory.WithWebHostBuilder(b => b.UseStartup<TestStartup>()).CreateClient();
        

        或者,您可以创建自己的自定义 WebApplicationFactory 并将其设置在那里:

        public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<RazorPagesProject.Startup>
        {
            protected override void ConfigureWebHost(IWebHostBuilder builder)
            {
                builder.UseStartup<TestStartup>();
            }
        }
        

        请记住,TStartup 泛型类型参数用于获取入口点程序集,因此您仍需将Startup 放在那里。

        这里的要点是你不需要重复所有的启动配置,然后记得保持同步。您的测试客户端将使用与您的实际应用完全相同的启动配置,除了一些保留替换,例如使用内存数据库。

        【讨论】:

        • 感谢您的建议,但在尝试后,我仍然收到与 contentRootPath 未设置相同的错误。
        【解决方案6】:

        我有一个非常简单的项目结构并遇到了同样的问题。项目结构:

        -repo_root
         - myProject
           - myProject.csproj
           - src
         - myProjectTest
           - myProjectTest.csproj
           - tests
        

        以上所有答案都不适合我。我浏览了docs 和其他与 WebApplicationFactoryContentRootAttribute 相关的来源,但无济于事。我还查看了 WebApplicationFactory implementation 并尝试在设置中使用 TEST_CONTENTROOT_APPNAME 无济于事。

        最终的帮助是在 repo_root 中创建了一个空的 myProject.sln 文件。

        【讨论】:

          猜你喜欢
          • 2022-06-16
          • 2019-03-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-12-10
          • 2018-04-10
          相关资源
          最近更新 更多