在集成測試ASP.NET Core Web API和EF Core時重新配置依賴關係

asp.net-core c# entity-framework-core integration-testing xunit2

我正在學習本教程
使用Entity Framework Core和SQL Server進行集成測試

我的代碼看起來像這樣

集成測試類

public class ControllerRequestsShould : IDisposable
{
    private readonly TestServer _server;
    private readonly HttpClient _client;
    private readonly YourContext _context;

    public ControllerRequestsShould()
    {
        // Arrange
        var serviceProvider = new ServiceCollection()
            .AddEntityFrameworkSqlServer()
            .BuildServiceProvider();

        var builder = new DbContextOptionsBuilder<YourContext>();

        builder.UseSqlServer($"Server=(localdb)\\mssqllocaldb;Database=your_db_{Guid.NewGuid()};Trusted_Connection=True;MultipleActiveResultSets=true")
            .UseInternalServiceProvider(serviceProvider);

        _context = new YourContext(builder.Options);
        _context.Database.Migrate();

        _server = new TestServer(new WebHostBuilder()
            .UseStartup<Startup>()
            .UseEnvironment(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")));
        _client = _server.CreateClient();
    }

    [Fact]
    public async Task ReturnListOfObjectDtos()
    {
        // Arrange database data
        _context.ObjectDbSet.Add(new ObjectEntity{ Id = 1, Code = "PTF0001", Name = "Portfolio One" });
        _context.ObjectDbSet.Add(new ObjectEntity{ Id = 2, Code = "PTF0002", Name = "Portfolio Two" });

        // Act
        var response = await _client.GetAsync("/api/route");
        response.EnsureSuccessStatusCode();


        // Assert
        var result = Assert.IsType<OkResult>(response);            
    }

    public void Dispose()
    {
        _context.Dispose();
    }

據我所知, .UseStartUp方法確保TestServer使用我的啟動類

我遇到的問題是當我的法案聲明被擊中時

var response = await _client.GetAsync("/api/route");

我的啟動類中出現連接字符串為空的錯誤。我想我對這個問題的理解是,當我的控制器從客戶端被命中時,它會注入我的數據存儲庫,而數據存儲庫又會注入數據庫上下文。

我認為我需要將服務配置為new WebHostBuilder部分的一部分,以便它使用測試中創建的上下文。但我不知道該怎麼做。

Startup.cs中的ConfigureServices方法

        public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services
        services.AddMvc(setupAction =>
        {
            setupAction.ReturnHttpNotAcceptable = true;
            setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
            setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter());
        });

        // Db context configuration
        var connectionString = Configuration["ConnectionStrings:YourConnectionString"];
        services.AddDbContext<YourContext>(options => options.UseSqlServer(connectionString));

        // Register services for dependency injection
        services.AddScoped<IYourRepository, YourRepository>();
    }

熱門答案

1.使用WebHostBuilder.ConfigureServices

過了一段時間,我認為最簡單的解決方案是使用WebHostBuilder.ConfigureServicesWebHostBuilder.UseStartup<T>來覆蓋和模擬Web應用程序的DI註冊:

_server = new TestServer(new WebHostBuilder()
    .ConfigureServices(services =>
    {
        services.AddScoped<IFooService, MockService>();
    })
    .UseStartup<Startup>()
);

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        //use TryAdd to support mocking the service
        services.TryAddTransient<IFooService, FooService>();
    }
}

這裡的關鍵是在Startup類中使用TryAdd方法。在原始Startup 之前調用WebHostBuilder.ConfigureServices ,所以首先註冊你的模擬。如果使用TryAdd則跳過實際服務的註冊。

更多信息: 運行ASP.NET核心應用程序的集成測試

2.繼承/新的啟動類

創建TestStartup類以重新配置ASP.NET Core DI。您可以從Startup繼承它並僅覆蓋所需的方法:

public class TestStartup : Startup
{
    public TestStartup(IHostingEnvironment env) : base(env) { }

    public override void ConfigureServices(IServiceCollection services)
    {
        //mock DbContext and any other dependencies here
    }
}

或者,可以從頭開始創建TestStartup以使測試更清晰。

並在UseStartup指定它來運行測試服務器:

_server = new TestServer(new WebHostBuilder().UseStartup<TestStartup>());

Ð完整的大例子: 使用內存數據庫集成測試你的asp .net核心應用程序



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow