You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.Net Core 7.0 Angular SPA集成测试WebApplicationFactory返回404问题

问题:ASP.Net Core 7.0 + Angular SPA集成测试返回404,传统Web App正常

我正在搭建包含集成测试的ASP.Net Core 7.0 + Angular SPA应用,使用WebApplicationFactory执行集成测试时,所有请求均返回404状态码。但将相同测试配置应用于传统ASP.Net Core Web App时,能正常返回页面及200状态码。我清楚页面由客户端渲染,但至少期望服务器能返回内容,请问我遗漏了什么配置?


Angular应用代码

主项目Program.cs

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseSetting(WebHostDefaults.ApplicationKey, typeof(Startup).Assembly.GetName().Name);
                webBuilder.UseStartup<Startup>();
            });

}

Startup.cs

public class Startup
{
    private readonly IConfiguration _configuration;

    public Startup(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public virtual void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
    }

    public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (!env.IsDevelopment())
        {
            // 默认HSTS有效期为30天,生产环境可按需调整
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller}/{action=Index}/{id?}");

            endpoints.MapFallbackToFile("index.html");
        });
    }
}

集成测试项目HomeControllerTests.cs

public class HomeControllerTests: IClassFixture<WebApplicationFactory<Startup>>
{
    private readonly WebApplicationFactory<Startup> _factory;

    public HomeControllerTests(WebApplicationFactory<Startup> factory)
    {
        _factory = factory;
    }

    [Theory]
    [InlineData("/")]
    [InlineData("/fetch-data")]
    public async Task Get_EndpointsReturnSuccessAndCorrectContentType(string url)
    {
        // Arrange
        using var client = _factory.CreateClient();
            
        // Act
        using var response = await client.GetAsync(url);

        // Assert
        response.EnsureSuccessStatusCode();
        Assert.Equal("text/html; charset=utf-8", response.Content.Headers.ContentType.ToString());
    }
}

传统Web应用代码

主项目Program.cs

public static class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseSetting(WebHostDefaults.ApplicationKey, typeof(Startup).Assembly.GetName().Name);
                webBuilder.UseStartup<Startup>();
            });

}

Startup.cs

public class Startup
{
    private readonly IConfiguration _configuration;

    public Startup(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public virtual void ConfigureServices(IServiceCollection services)
    {
        // 向容器添加服务
        services.AddRazorPages();
    }

    public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // 配置HTTP请求管道
        if (!env.IsDevelopment())
        {
            app.UseExceptionHandler("/Error");
            // 默认HSTS有效期为30天,生产环境可按需调整
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
        });
    }
}

集成测试项目HomeControllerTests.cs

public class HomeControllerTests: IClassFixture<WebApplicationFactory<Startup>>
{
    private readonly WebApplicationFactory<Startup> _factory;
    
    public HomeControllerTests(WebApplicationFactory<Startup> factory)
    {
        _factory = factory;
    }
    
    [Theory]
    [InlineData("/")]
    [InlineData("/Privacy")]
    public async Task Get_EndpointsReturnSuccessAndCorrectContentType(string url)
    {
        // Arrange
        using var client = _factory.CreateClient();
            
        // Act
        using var response = await client.GetAsync(url);

        // Assert
        response.EnsureSuccessStatusCode();
        Assert.Equal("text/html; charset=utf-8", response.Content.Headers.ContentType.ToString());
    }
}

解决方案

核心原因是:Angular SPA的静态文件(比如index.html)需要通过ng build编译生成,默认不会被WebApplicationFactory在测试环境中自动加载;而传统Web App的Razor Pages文件属于项目编译资源,测试时会被自动包含。

1. 确保静态文件可被测试环境访问

  • 先构建Angular项目:运行ng build命令生成编译后的静态文件(默认在ClientApp/dist目录,根据你的项目结构调整路径)。
  • 配置静态文件路径:修改Startup.cs中的UseStaticFiles,指定Angular编译后的文件目录:
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.ContentRootPath, "ClientApp/dist")), // 替换为你的Angular dist实际路径
        RequestPath = ""
    });
    
  • 调整测试项目的内容根目录:自定义WebApplicationFactory,让测试环境指向主项目目录,确保能找到静态文件:
    public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
    {
        protected override void ConfigureWebHost(IWebHostBuilder builder)
        {
            // 替换为你的ASP.Net Core主项目相对路径
            var mainProjectPath = Path.Combine(Directory.GetCurrentDirectory(), "../YourAspNetCoreProject");
            builder.UseContentRoot(mainProjectPath);
            base.ConfigureWebHost(builder);
        }
    }
    
    然后测试类继承这个自定义工厂:
    public class HomeControllerTests: IClassFixture<CustomWebApplicationFactory<Startup>>
    {
        // 其余代码保持不变
    }
    

2. 验证Fallback路由有效性

你已经配置了endpoints.MapFallbackToFile("index.html");,这是SPA必备的路由回退规则,但要确保index.html确实存在于你配置的静态文件目录中。

3. 避免测试环境禁用静态文件

检查代码中是否有条件性禁用UseStaticFiles的逻辑(比如只在开发环境启用),确保测试环境下静态文件中间件正常工作。

可选:自动构建Angular(无需手动执行ng build)

可以在测试项目的构建事件中添加命令,自动触发Angular构建:

cd "$(SolutionDir)ClientApp"
ng build --configuration production

这样每次运行测试前都会自动构建Angular,确保静态文件是最新的。


内容的提问来源于stack exchange,提问作者DeLoooping

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 08:03:01