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

.NET Core 6.0单元测试:如何正确注册带构造依赖的服务?

单元测试获取服务失败问题解决

问题描述

运行获取天气列表的单元测试时,出现无法从服务提供程序中获取类型为WeatherServiceManager的服务,因为该服务未注册的报错。


相关代码

1. 服务注册类(ApplicationRegister)

public static class ApplicationService
{
    /// <summary>
    /// Method to configure application level services with the di container
    /// </summary>
    /// <param name="services"></param>
    /// <param name="configuration"></param>
    public static void ConfigureApplicationServices(this IServiceCollection services)
    {
          services.AddScoped<IWeatherServiceManager, WeatherServiceManager>();
          services.AddScoped<IHttpClientApiService, HttpClientApiService>();
    }
}

2. Program.cs 服务注册片段

using weather_api.ServiceRegister;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

#region [Register Services]
builder.Services.ConfigureApplicationServices();
#endregion

3. WeatherServiceManager 实现类

public class WeatherServiceManager : IWeatherServiceManager
{
    private readonly IHttpClientApiService httpClientApiService;
    private readonly IConfiguration configuration;

    public WeatherServiceManager(IHttpClientApiService httpClientApiService, IConfiguration configuration)
    {
        this.httpClientApiService = httpClientApiService;
        this.configuration = configuration;
    }
   
}

4. 单元测试类

public class WeatherControllerTest
{
    private readonly IWeatherServiceManager _weatherServiceManager;

    public WeatherControllerTest()
    {
        var services = new ServiceCollection();
        var serviceProvider = services.BuildServiceProvider();
        _weatherServiceManager = serviceProvider.GetRequiredService<WeatherServiceManager>();

    }

    /// <summary>
    /// Get Weather details using zip code and city name
    /// </summary>
    /// <returns></returns>
    [Fact]
    public async Task GetWeatherInformation()
    {
        // Act & Assert
        var items = Assert.IsType<List<WeatherViewModel>>(await _weatherServiceManager.GetForecast("London"));
        Assert.Equal(3, items.Count);
    }

}

问题原因及修复方案

核心原因

单元测试构造函数里只创建了空的ServiceCollection,完全没有注册任何服务,直接调用GetRequiredService必然报错。另外WeatherServiceManager还依赖IHttpClientApiService和IConfiguration,就算注册了自身,这两个依赖也缺失。

修复步骤

  1. 注册必要服务:在测试的服务集合中注册所需服务,可直接复用已有的ConfigureApplicationServices扩展方法。
  2. 提供模拟配置:测试环境用内存配置模拟IConfiguration。
  3. Mock外部依赖:对IHttpClientApiService这类调用外部API的服务,用Mock对象替代真实实现,避免依赖外部服务。

修复后的单元测试示例(使用Moq实现Mock):

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Moq;

public class WeatherControllerTest
{
    private readonly IWeatherServiceManager _weatherServiceManager;

    public WeatherControllerTest()
    {
        var services = new ServiceCollection();
        
        // 1. 添加模拟配置
        var testConfig = new ConfigurationBuilder()
            .AddInMemoryCollection(new Dictionary<string, string>
            {
                {"WeatherApi:BaseUrl", "https://test-api.example.com"}
            })
            .Build();
        services.AddSingleton<IConfiguration>(testConfig);
        
        // 2. Mock IHttpClientApiService,返回测试用固定数据
        var httpClientMock = new Mock<IHttpClientApiService>();
        httpClientMock.Setup(x => x.GetAsync<List<WeatherViewModel>>(It.IsAny<string>()))
                      .ReturnsAsync(new List<WeatherViewModel> { new(), new(), new() });
        services.AddSingleton(httpClientMock.Object);
        
        // 3. 注册WeatherServiceManager
        services.AddScoped<IWeatherServiceManager, WeatherServiceManager>();
        
        var serviceProvider = services.BuildServiceProvider();
        _weatherServiceManager = serviceProvider.GetRequiredService<IWeatherServiceManager>();
    }

    [Fact]
    public async Task GetWeatherInformation()
    {
        // Act
        var items = await _weatherServiceManager.GetForecast("London");
        
        // Assert
        Assert.IsType<List<WeatherViewModel>>(items);
        Assert.Equal(3, items.Count);
    }
}

额外提示

单元测试重点是验证WeatherServiceManager的业务逻辑,而非调用真实外部API,所以用Mock隔离外部依赖是标准做法。如果不想用Moq,也可以手动写一个IHttpClientApiService的测试实现类,返回固定测试数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 18:20:47