[英]WebApplicationFactory throws error that contentRootPath does not exist in ASP.NET Core integration test
我有一个 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.UseContentRoot
和builder.UseSolutionRelativeContentRoot
配置自定义WebApplicationFactory ,但无论我为ContentRoot
方法使用什么值,它都会抛出相同的错误。
我不知道为什么我的测试失败,而 Clean Architecture 示例中的测试正在运行。 我也不知道怎么修。
任何指针都非常感谢!
这个方法对我有用
var client = _factory
.WithWebHostBuilder(builder => builder.UseSolutionRelativeContentRoot("relative/path/of/project/under/test"))
.CreateClient();
有关更多信息,请参阅测试基础架构如何推断应用内容根路径。
我对这个问题的解决方法是定义WebApplicationFactory
与应用程序启动,但在安装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);
}
}
似乎 WebApplicationFactory 应该使用真正的 Startup 类作为参数类型:
class TestWebApplicationFactory : WebApplicationFactory<Startup>
{
protected override IWebHostBuilder CreateWebHostBuilder()
{
return WebHost.CreateDefaultBuilder<TestableStartup>();
}
}
请注意,Startup 是真实 SUT 代码上的类型,而 TestableStartup 是 TestingStartup 配置。
如果您使用的是 ReSharper,它很可能与版本有关。 我们发现了 2018.3 版本的问题。 添加 UseSolutionRelativeContentRoot 解决了它。
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.UseKestrel()
.UseSolutionRelativeContentRoot("")
.ConfigureAppConfiguration((context, configBuilder) =>
{
// Config code
})
.UseStartup<Startup>();
}
我不完全确定你在说什么,但首先你不应该在测试项目中配置这样的东西。 相反,您应该创建一个类似TestStartup
的类并从 SUT 的Startup
类继承。 在 SUT 的Startup
类中,您应该将诸如数据库设置之类的内容分解为虚拟私有方法,然后您可以在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
放在那里。
这样做的要点是你不需要重复所有的启动配置,然后记住保持同步。 您的测试客户端将使用与您的实际应用程序使用完全相同的启动配置,除了一些保留替代品,如使用内存数据库。
我有一个非常简单的项目结构并遇到了同样的问题。 项目结构:
-repo_root
- myProject
- myProject.csproj
- src
- myProjectTest
- myProjectTest.csproj
- tests
以上所有答案都不适用于我。 我浏览了与 WebApplicationFactoryContentRootAttribute 相关的文档和其他来源,但无济于事。 我还研究了 WebApplicationFactory 实现并尝试在设置中使用 TEST_CONTENTROOT_APPNAME 无济于事。
最后有什么帮助是在 repo_root 中创建一个空的 myProject.sln 文件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.