我尝试用NUnit和Asp.net-core-hosted Blazor WebAssembly应用程序编写端到端测试。
我用3.1.7模板创建了一个新项目。然后我只添加一个NUnit项目并编写简单的测试。
private const string serviceUrl = "https://localhost:50200";
private HttpClient _httpClient;
[OneTimeSetUp]
public void Init()
{
var arguments = new string[0];
var builder = Program.CreateHostBuilder(arguments);
_httpClient = new HttpClient();
builder
.ConfigureWebHostDefaults(w => w.UseUrls(serviceUrl))
.Build()
.Start();
}
[Test]
public async Task HomePageResponcesOk()
{
var requestUrl = serviceUrl;
var response = await _httpClient.GetAsync(requestUrl);
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
[Test]
public async Task ApiResponcesOk()
{
var requestUrl = $"{serviceUrl}/WeatherForecast";
var response = await _httpClient.GetAsync(requestUrl);
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
我什么都没改变。
我得到下一个结果
Test Duration Error Message
HomePageResponcesOk Failed 45 ms Expected: OK But was: NotFound
ApiResponcesOk Passed 364 ms
我做错了什么?
我可以指出,它在更早期的Blazor WebAssembly版本中运行良好。
我添加了另外两个测试
[Test]
public async Task AppCssResponcesOk()
{
var requestUrl = $"{serviceUrl}/css/app.css";
var response = await _httpClient.GetAsync(requestUrl);
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
[Test]
public async Task WebAssemblyResponcesOk()
{
var requestUrl = $"{serviceUrl}/_framework/blazor.webassembly.js";
var response = await _httpClient.GetAsync(requestUrl);
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
它们返回相同的结果CCD_ 1。
我认为app.UseStaticFiles();
并不像我预期的那样工作。这可能是真的吗?如何修复?
因此,当测试项目开始时,后端不知道wwwroot在哪里。可以用UseWebRoot()
修复。
builder
.ConfigureWebHostDefaults(w =>
{
w.UseUrls(serviceUrl);
w.UseWebRoot(@"........BlazorApp2Clientwwwroot");
})
.Build()
.Start();
除WebAssemblyResponcesOk()
外,所有测试均成功通过。这是由于文件被放置在另一个目录BlazorApp2ClientbinDebugnetstandard2.1wwwroot_framework
中。如果我添加第二个.UseWebRoot()
,则仅取消第一个。
好的,我用调试器深入研究ASP.Net核心的源代码。
接下来就是事实。
如果运行后端项目,则类StaticFileMiddleware
中的_fileProvider
字段将获得一个具有下一个结构的复杂值:
CompositeFileProvider-- ._fileProviders
|
+-- NullFileProvider
|
+-- StaticWebAssetsFileProvider-- .InnerProvider
|
PhysicalFileProvider
|
+-- StaticWebAssetsFileProvider-- .InnerProvider
|
PhysicalFileProvider
一个PhysicalFileProvider
的目标是源代码中的wwwroot,另一个目标是Failed 45 ms Expected: OK But was: NotFound
0中的wwwroot。
如果运行测试,StaticFileMiddleware
_fileProvider
会得到简单的PhysicalFileProvider
目标,就像UseWebRoot()
参数一样。如果我返回到没有UseWebRoot()
的版本,NullFileProvider
会被设置在那里。
现在我意识到一开始发生了什么。但我仍然不知道什么对StaticFileMiddleware文件提供程序有确切的影响。类构造器通过注入IOptions<StaticFileOptions>
来获得值。
我应该在哪里设置断点来捕获这种类型的DI注册?
根据您收到的响应,即"NotFound">,我的第一个猜测是,为获取特定文件而创建的路径可能不正确。如果我要调试它,我可能会尝试一些"MapFallbackToFile"函数的重载。需要显式路径(绝对路径或相对路径(或其他属性的路径。经过一段时间的试用,您可能能够找到相应的文件。
为了加快调试过程,您可以做的另一件事是通过编程检查当前工作目录,并将其用作构建所需准确文件路径的参考点。这可以使用以下命令完成:
System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
一个非常常见的错误是,我们的程序通常在构建目录(例如bin/debug/..(中运行,而我们所需的文件(例如css或image(文件不在那里,因此,我们会遇到这样的问题。这是解决这个问题的一种方法。
-
我已将*.StaticWebAssets.xml文件从
...ServerbinDebugnetcoreapp3.1
复制到...NUnitTestProject1binDebugnetcoreapp3.1
-
我已将
UseStaticWebAssets()
添加到后端启动代码中。builder .ConfigureWebHostDefaults(w => { w.UseUrls(serviceUrl); w.UseStaticWebAssets(); }) .Build() .Start();
所有测试都通过了。调试器显示CompositeFileProvider
注入,其结构与后端启动手动时相同。。。
我已经在构建事件中设置了这些文件的复制
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="copy ..Restbin$(ConfigurationName)net5.0-windows*.StaticWebAssets.xml .bin$(ConfigurationName)net5.0-windows*.*" />
</Target>
很遗憾,我没有意识到如何在测试项目中实现自动生成StaticWebAssets.xml。