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

.NET Core 6 API Xunit单元测试依赖注入报错问题排查

.NET Core 6 Xunit单元测试依赖注入问题排查与解决

问题场景

在.NET Core 6 API项目中使用Xunit测试ICrpForcastsService接口的实现类CrpForcastsService,编写了测试类、Fixture类和Startup类,但运行测试时出现错误:

(No service for type 'Microsoft.AspNetCore.Builder.IApplicationBuilder' has been registered.) (The following constructor parameters did not have matching fixture data: ICrpForcastsService crpForcastsService)

测试类代码

public class ForcastTester: IClassFixture<InjectionFixture>
{
    private readonly InjectionFixture injection;
    private readonly Psz.Core.Identity.Models.UserModel _user;
    private readonly ICrpForcastsService _crpForcastsService;
    public ForcastTester(InjectionFixture injection, ICrpForcastsService crpForcastsService)
    {
        this.injection = injection;
        var helpers = new TestingHelpers();
        _user = helpers.GetDefaultTestUser();
        _crpForcastsService = crpForcastsService;
    }
    [Fact]
    public void TestGetForecasts()
    {
        #region Arrange
        var expected = typeof(Psz.Core.Common.Models.ResponseModel<IEnumerable<Psz.Core.CRP.Models.Forcasts.ForcastHeaderModel>>);
        #endregion
        #region Act
        var result = _crpForcastsService.GetForcasts(_user);
        #endregion
        #region Assert
        Assert.NotNull(result);
        Assert.NotNull(result.Body);
        Assert.True(result.Success);
        Assert.IsType(expected, result);
        Assert.True(result.Body.Count() > 0);
        #endregion
    }
}

Fixture类代码

public class InjectionFixture
{
    public readonly TestServer server;
    private readonly HttpClient client;

    public InjectionFixture()
    {
        server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
        client = server.CreateClient();
    }
    public IServiceProvider ServiceProvider => server.Host.Services;

    public void Dispose()
    {
        Dispose(true);
    }
    protected virtual void Dispose(bool disposing)
    {
        if(disposing)
        {
            server.Dispose();
            client.Dispose();
        }
    }
}

Startup类代码

public class Startup
{
    public Startup()
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddEnvironmentVariables();
        Configuration = builder.Build();
    }
    public IConfigurationRoot Configuration { get; }
    public virtual void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<ICrpForcastsService, CrpForcastsService>();
        services.AddControllers();
    }
    public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
    }
}

错误原因与修复步骤

1. 测试类构造函数无法直接注入服务

Xunit的Fixture机制不会自动解析并注入容器中的服务,测试类构造函数里的ICrpForcastsService参数无法被自动匹配。需要通过Fixture提供的ServiceProvider手动获取服务实例。

修改测试类构造函数:

public ForcastTester(InjectionFixture injection)
{
    this.injection = injection;
    var helpers = new TestingHelpers();
    _user = helpers.GetDefaultTestUser();
    // 从Fixture的服务容器中获取目标服务
    _crpForcastsService = injection.ServiceProvider.GetRequiredService<ICrpForcastsService>();
}

2. 替换测试服务器初始化方式(解决IApplicationBuilder注册问题)

自定义TestServer初始化方式在.NET Core 6中可能存在兼容性问题,建议改用官方推荐的WebApplicationFactory来创建测试服务器,它会自动处理应用构建的依赖项。

替换原InjectionFixture为:

public class InjectionFixture : WebApplicationFactory<Startup>
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureServices(services =>
        {
            // 可在此处覆盖或添加测试专用的服务配置
            services.AddScoped<ICrpForcastsService, CrpForcastsService>();
        });
    }
}

3. 确保测试项目能读取配置文件

右键测试项目中的appsettings.json文件,设置复制到输出目录属性为「如果较新则复制」,避免因配置文件缺失导致服务初始化异常。

4. 纯单元测试场景的轻量方案(可选)

如果只是测试服务的业务逻辑而非集成测试,可以直接构建独立的服务容器,无需启动测试服务器:

public class InjectionFixture : IDisposable
{
    public IServiceProvider ServiceProvider { get; }

    public InjectionFixture()
    {
        var services = new ServiceCollection();
        var configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: true)
            .Build();

        services.AddSingleton<IConfiguration>(configuration);
        services.AddScoped<ICrpForcastsService, CrpForcastsService>();
        // 添加服务依赖的其他组件

        ServiceProvider = services.BuildServiceProvider();
    }

    public void Dispose()
    {
        if (ServiceProvider is IDisposable disposable)
        {
            disposable.Dispose();
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 04:53:17