.net core 3.0,IClassFixture问题,“未解决的构造函数参数:ITestOutputHelper输出”

时间:2019-12-03 23:14:56

标签: c# xunit .net-core-3.0

我针对集成测试升级到.net core 3.0时遇到的问题进行了回购: https://github.com/ranouf/TestingWithDotNetCore3_0

启动测试时,出现以下问题: 讯息:

  

System.AggregateException:发生一个或多个错误。 (类夹具类型“ MyIntegrationTests.TestServerFixture”具有一个或多个   尚未解决的构造函数参数:ITestOutputHelper输出)(   以下构造函数参数没有匹配的灯具数据:   TestServerFixture testServerFixture)       ----类夹具类型“ MyIntegrationTests.TestServerFixture”具有一个或多个未解析的构造函数参数:ITestOutputHelper输出       ----以下构造函数参数没有匹配的夹具数据:TestServerFixture testServerFixture堆栈跟踪:       -----内部堆栈跟踪#1(Xunit.Sdk.TestClassException)-----       -----内部堆栈跟踪2(Xunit.Sdk.TestClassException)-----

这里是构造函数:

public class WeatherForecastController_Tests : IClassFixture<TestServerFixture>
{
    public WeatherForecastController_Tests(TestServerFixture testServerFixture, ITestOutputHelper output)
    {
        Client = testServerFixture.Client;
        Output = output;
    }

TestStartup:

public class TestStartup : Startup
{
    public TestStartup(IConfiguration configuration)
        : base(configuration)
    {

    }

    public override void SetUpDataBase(IServiceCollection services)
    {
        // here is where I use the InMemoryDatabase 
    }
}

TestServerFixture:

public class TestServerFixture : WebApplicationFactory<TestStartup>
{
    private IHost _host;
    public HttpClient Client { get; }
    public ITestOutputHelper Output { get; }

    public TestServerFixture(ITestOutputHelper output)
    {
        Output = output;
        Client = Server.CreateClient();
    }

    // never called but this is where i was previously building up the server
    //
    protected override TestServer CreateServer(IWebHostBuilder builder)
    {
        return base.CreateServer(builder);
    }

    protected override IHost CreateHost(IHostBuilder builder)
    {
        _host = builder.Build();

        using (var scope = _host.Services.CreateScope())
        {
            var services = scope.ServiceProvider;
            InitializeDataBase(services, Output);
        }

        _host.Start();
        return _host;
    }

    protected override IHostBuilder CreateHostBuilder() =>
        Host.CreateDefaultBuilder()
            .ConfigureLogging((hostingContext, builder) =>
            {
                builder.Services.AddSingleton<ILoggerProvider>(new XunitLoggerProvider(Output));
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseTestServer();
            });

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.UseStartup<TestStartup>();
    }

    private void InitializeDataBase(IServiceProvider services, ITestOutputHelper output)
    {
        try
        {
            output.WriteLine("Starting the database initialization.");
            //here is where is feed the Test DB
            output.WriteLine("The database initialization has been done.");
        }
        catch (Exception ex)
        {
            output.WriteLine("An error occurred while initialization the database.");
            Console.WriteLine(ex.Message);
        }
    }
}

很明显,TestServerFixture的Iod testServerFixture和ITestOutputHelper输出不起作用。如何运作?

2 个答案:

答案 0 :(得分:1)

我检查了您的代码,经过研究后得出的结论是,通过构造函数注入将ITestOutputHelper注入TestServerFixture是不可行的。我也研究过资产注入,但我相信它可能最终会在资产填充之前被使用。

这里的主要问题是创建WebApplicationFactory时如何调用事物的流程。

通过在构造函数中创建Client,它会触发一系列事件,使您无法利用ITestOutputHelper

我建议推迟创建Client,以便可以先设置依赖项。

public class TestServerFixture : WebApplicationFactory<TestStartup> {
    private Lazy<HttpClient> client = new Lazy<HttpClient>(() => return Server.CreateClient());

    private IHost _host;
    public HttpClient Client => client.Value;
    public ITestOutputHelper Output { get; set; }

    public TestServerFixture(){
        //...
    }

    //...all other code remains the same
}

请注意Lazy<HttpClient>。这是为了延迟客户端的创建,以便可以首先填充ITestOutputHelper

public class WeatherForecastController_Tests : IClassFixture<TestServerFixture> {
    public WeatherForecastController_Tests(TestServerFixture testServerFixture, ITestOutputHelper output) {
        Output = output;
        testServerFixture.Output = Output;
        Client = testServerFixture.Client;            
    }

    //...

答案 1 :(得分:0)

感谢@Nkosi的帮助,它帮助我找到了解决方案:)。 我也受到其他网站的启发:

我也在仓库上更新了解决方案

以下是重要部分:

TestServerFixture:

public class TestServerFixture : WebApplicationFactory<TestStartup>
{
    public HttpClient Client { get; }
    public ITestOutputHelper Output { get; set; }

    protected override IHostBuilder CreateHostBuilder()
    {
        var builder = Host.CreateDefaultBuilder()
            .ConfigureLogging(logging =>
            {
                logging.ClearProviders(); //All API logging providers are cleared
                logging.AddXunit(Output); //Internal extension which redirect all log to the ITestOutputHelper 
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder
                    .UseStartup<TestStartup>()
                    .ConfigureTestServices((services) =>
                    {
                        //Without that, the client always returns 404
                        //(even if it has already been set in Startup.Configure)
                        services
                            .AddControllers()
                            .AddApplicationPart(typeof(Startup).Assembly);
                    });
            });

        return builder;
    }

    //ITestOutputHelper is set in the constructor of the Test class
    public TestServerFixture SetOutPut(ITestOutputHelper output)
    {
        Output = output;
        return this;
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        Output = null;
    }
}

WeatherForecastController_Tests:

public class WeatherForecastController_Tests : IClassFixture<TestServerFixture>
{
    public TestServerFixture TestServerFixture { get; private set; }
    public HttpClient Client { get; private set; }
    public ITestOutputHelper Output { get { return TestServerFixture.Output; } }

    public WeatherForecastController_Tests(TestServerFixture testServerFixture, ITestOutputHelper output)
    {
        TestServerFixture = testServerFixture.SetOutPut(output);
        Client = testServerFixture.CreateClient();
    }

    [...]
}

如果您有任何改进代码或问题的建议,请告诉我:)