WebApplicationFactory 抛出 ASP.NET Core 集成测试中不存在 contentRootPath 的错误

Wou*_*ort 16 c# integration-testing asp.net-core

我有一个 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
Run Code Online (Sandbox Code Playgroud)

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

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

任何指针都非常感谢!

Kit*_*Kit 12

这个方法对我有用

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

有关更多信息,请参阅测试基础架构如何推断应用内容根路径


小智 10

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

例子:

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

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.UseStartup<TestStartup>();

        base.ConfigureWebHost(builder);
    }
}
Run Code Online (Sandbox Code Playgroud)


cyb*_*tes 7

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

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

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


Jim*_*ods 6

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

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


Chr*_*att 5

我不完全确定你在说什么,但你首先不应该在测试项目中配置这样的东西。相反,您应该创建一个类似TestStartupSUT 类的类并继承该类Startup。在 SUT 的Startup类中,您应该将数据库设置等内容分解为虚拟私有方法,然后您可以在TestStartup. 例如,您可以创建如下方法:

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

然后在你的 中TestStartup,你可以添加类似的内容:

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

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

var client = factory.WithWebHostBuilder(b => b.UseStartup<TestStartup>()).CreateClient();
Run Code Online (Sandbox Code Playgroud)

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

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

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

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