简体   繁体   English

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

[英].net core 3.0, issue with IClassFixture, "unresolved constructor arguments: ITestOutputHelper output"

I made a repo for the issue I have with Integration testing upgrading to .net core 3.0 : https://github.com/ranouf/TestingWithDotNetCore3_0我为集成测试升级到 .net core 3.0 的问题制作了一个 repo: https : //github.com/ranouf/TestingWithDotNetCore3_0

When I launch the test, I have this issue: Message:当我启动测试时,我遇到了这个问题:消息:

System.AggregateException : One or more errors occurred. System.AggregateException :发生一个或多个错误。 (Class fixture type 'MyIntegrationTests.TestServerFixture' had one or more unresolved constructor arguments: ITestOutputHelper output) (The following constructor parameters did not have matching fixture data: TestServerFixture testServerFixture) ---- Class fixture type 'MyIntegrationTests.TestServerFixture' had one or more unresolved constructor arguments: ITestOutputHelper output ---- The following constructor parameters did not have matching fixture data: TestServerFixture testServerFixture Stack Trace: ----- Inner Stack Trace #1 (Xunit.Sdk.TestClassException) ----- ----- Inner Stack Trace #2 (Xunit.Sdk.TestClassException) ----- (类夹具类型“MyIntegrationTests.TestServerFixture”有一个或多个未解析的构造函数参数:ITestOutputHelper 输出)(以下构造函数参数没有匹配的夹具数据:TestServerFixture testServerFixture)----类夹具类型“MyIntegrationTests.TestServerFixture”有一个或更多未解析的构造函数参数: ITestOutputHelper 输出 ---- 以下构造函数参数没有匹配的夹具数据: TestServerFixture testServerFixture Stack Trace: ----- 内部堆栈跟踪 #1 (Xunit.Sdk.TestClassException) ----- - ---- 内部堆栈跟踪 #2 (Xunit.Sdk.TestClassException) -----

Here is the constructor:这是构造函数:

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);
        }
    }
}

So clearly, the Iod for TestServerFixture testServerFixture and ITestOutputHelper output doesnt work.很明显,TestServerFixture testServerFixture 和 ITestOutputHelper 输出的 Iod 不起作用。 How to make it work?如何使它工作?

Thanks @Nkosi for your help, It helps me to find a solution :).感谢@Nkosi 的帮助,它帮助我找到解决方案:)。 I was inspired by other websites too:我也受到了其他网站的启发:

I updated the solution on my repo too我也更新了我的回购解决方案

Here are important parts:以下是重要部分:

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: 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();
    }

    [...]
}

Let me know if you have any suggestions to improve the code or questions :)如果您有任何改进代码的建议或问题,请告诉我:)

I reviewed your code and after some research I have come to the conclusion that injecting ITestOutputHelper into TestServerFixture via constructor injection is not feasible.我查看了您的代码,经过一些研究,我得出的结论是,通过构造函数注入将ITestOutputHelper注入TestServerFixture是不可行的。 I looked into property injection as well but I believe the it may end up getting used before the property has been populated.我也研究了财产注入,但我相信它可能最终会在财产被填充之前被使用。

The main issue here is the flow of how things get invoked when the WebApplicationFactory is created.这里的主要问题是创建WebApplicationFactory时如何调用事物的流程。

By creating the Client in the constructor, it triggers a sequence of events that prevent you from being able to make use of the ITestOutputHelper通过在构造函数中创建Client ,它会触发一系列事件,阻止您使用ITestOutputHelper

I suggest deferring the creation of the Client so that dependencies can be set before.我建议推迟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
}

Note the Lazy<HttpClient> .注意Lazy<HttpClient> This is to defer the creation of the client so that the ITestOutputHelper can be populate first.这是为了推迟客户端的创建,以便可以首先填充ITestOutputHelper

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

    //...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM