ASP.NET Core 测试 - 没有 'public static IHostBuilder CreateHostBuilder(string[] args)' 方法

18

我正在尝试在测试中设置我的应用程序,并在StartupConfigure方法中使用context.Database.EnsureCreated(),期望Sqlite文件出现在Test的二进制文件夹中。

这是我的代码:

using Microsoft.AspNetCore.Mvc.Testing;
using System.Threading.Tasks;
using Xunit;

namespace MyApp.Tests
{
    public class UnitTest1 : IClassFixture<CustomWebApplicationFactory<FakeStartup>>
    {
        private readonly CustomWebApplicationFactory<FakeStartup> _factory;

        public UnitTest1(CustomWebApplicationFactory<FakeStartup> factory)
        {
            _factory = factory;
        }

        [Fact]
        public async Task Test1()
        {
            // Arrange
            var client = _factory.CreateClient();

            // Act
            var response = await client.GetAsync("https://localhost:5001/");

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

正在使用WebAppFactory的内容:

using MyApp.Tests;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;

public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.UseStartup<FakeStartup>();
    }
}

假设FakeStartup是:

using MyApp.Database;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;

namespace MyApp.Tests
{
    public class FakeStartup
    {
        public FakeStartup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {            
            services.AddControllers();

            services.AddDbContext<Context>(x => x.UseSqlite($"filename={Guid.NewGuid():N}.db"));

            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "Test API", Version = "v1" });
            });
        }
    }

    public static void Configure(IApplicationBuilder app, IWebHostEnvironment env, Context context)
    {
        context.Database.EnsureDeleted();
        context.Database.EnsureCreated();

        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "Test API v1");
            c.RoutePrefix = string.Empty;
        });

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseForwardedHeaders(new ForwardedHeadersOptions
        {
            ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
        });

        app.UseAuthentication();

        app.UseCors(x =>
        {
            x.AllowAnyOrigin();
            x.AllowAnyMethod();
            x.AllowAnyHeader();
        });

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthorization();

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

以下是问题:

  Message: 
    System.InvalidOperationException : No method 'public static IHostBuilder CreateHostBuilder(string[] args)' or 'public static IWebHostBuilder CreateWebHostBuilder(string[] args)' found on 'AutoGeneratedProgram'. Alternatively, WebApplicationFactory`1 can be extended and 'CreateHostBuilder' or 'CreateWebHostBuilder' can be overridden to provide your own instance.
  Stack Trace: 
    WebApplicationFactory`1.CreateWebHostBuilder()
    WebApplicationFactory`1.EnsureServer()
    WebApplicationFactory`1.CreateDefaultClient(DelegatingHandler[] handlers)
    WebApplicationFactory`1.CreateDefaultClient(Uri baseAddress, DelegatingHandler[] handlers)
    WebApplicationFactory`1.CreateClient(WebApplicationFactoryClientOptions options)
    WebApplicationFactory`1.CreateClient()
    UnitTest1.Test1() line 20
    --- End of stack trace from previous location where exception was thrown

这可能是什么原因造成的?提前致谢。

2个回答

32

获得CoreyP的评论后进行更新:

如果您在使用.NET 6.0时遇到此错误,则可能需要更新Microsoft.AspNetCore.Mvc.Testing包,请参见此问题:Integration test for ASP.NET Core 6 web API throws System.InvalidOperationException

解决方案:

按照以下方式创建CustomWebApplicationFactory

public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
    protected override IHostBuilder CreateHostBuilder()
    {
        var builder = Host.CreateDefaultBuilder()
                          .ConfigureWebHostDefaults(x =>
                          {
                              x.UseStartup<FakeStartup>().UseTestServer();
                          });
        return builder;
    }
}

在这里找到:

https://thecodebuzz.com/no-method-public-static-ihostbuilder-createhostbuilder/


1
据我所知,dotnet core 3.1不支持UseTestServer()。您是否有适用于.net core 3.1的解决方案? - PMO1948
@PMO1948 我正在使用它在.NET 5上,所以我很惊讶它不是.NET Core 3.1的一部分。 - Mathias Lykkegaard Lorenzen
嘿,那其实是我的错误 - 我试图在3.1中使用2.2版本,这就是为什么它没有工作的原因。 - PMO1948
1
如果您正在寻找dotnet 6.0,请查看此答案 - Corey P
嗨,我有一个问题需要解决。我的sln文件在一个文件夹中,而项目在“src”子文件夹中。当创建WebApplicationFactory时,它尝试在SLN文件的同一目录中查找My.Test.Folder。我该如何解决这个问题,而不必创建空文件夹? - Pierpaolo Paris
@CoreyP 我觉得你的评论值得更多的关注,我更新了这个答案,但也许你可以把它作为一个单独的答案发表? - Wiebe Tijsma

3
因为我没有仔细遵循 微软先决条件,所以出现了这个错误。在我的情况下,我没有在测试 csproj 文件中更新项目 SDK。它需要是 <Project Sdk="Microsoft.NET.Sdk.Web">(注意结尾处的'.Web')。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接