.net 核心 3.0,IClassFixture 问题,"unresolved constructor arguments: ITestOutputHelper output"
.net core 3.0, issue with IClassFixture, "unresolved constructor arguments: ITestOutputHelper output"
我为集成测试升级到 .net core 3.0 时遇到的问题做了一个回购:
https://github.com/ranouf/TestingWithDotNetCore3_0
当我启动测试时,我遇到了这个问题:
消息:
System.AggregateException : One or more errors occurred. (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) -----
这是构造函数:
public class WeatherForecastController_Tests : IClassFixture<TestServerFixture>
{
public WeatherForecastController_Tests(TestServerFixture testServerFixture, ITestOutputHelper output)
{
Client = testServerFixture.Client;
Output = output;
}
测试启动:
public class TestStartup : Startup
{
public TestStartup(IConfiguration configuration)
: base(configuration)
{
}
public override void SetUpDataBase(IServiceCollection services)
{
// here is where I use the InMemoryDatabase
}
}
测试服务器夹具:
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 testServerFixture 和 ITestOutputHelper 输出的 Iod 不起作用。如何让它发挥作用?
我查看了您的代码,经过一些研究后我得出结论,通过构造函数注入将 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;
}
//...
感谢@Nkosi 的帮助,它帮助我找到了解决方案:)。
我也受到了其他网站的启发:
- https://andrewlock.net/converting-integration-tests-to-net-core-3/
- https://gunnarpeipman.com/aspnet-core-integration-test-startup/
我也在我的 repo 上更新了解决方案
以下是重要部分:
测试服务器夹具:
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();
}
[...]
}
如果您有任何改进代码的建议或问题,请告诉我:)
我为集成测试升级到 .net core 3.0 时遇到的问题做了一个回购: https://github.com/ranouf/TestingWithDotNetCore3_0
当我启动测试时,我遇到了这个问题: 消息:
System.AggregateException : One or more errors occurred. (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) -----
这是构造函数:
public class WeatherForecastController_Tests : IClassFixture<TestServerFixture>
{
public WeatherForecastController_Tests(TestServerFixture testServerFixture, ITestOutputHelper output)
{
Client = testServerFixture.Client;
Output = output;
}
测试启动:
public class TestStartup : Startup
{
public TestStartup(IConfiguration configuration)
: base(configuration)
{
}
public override void SetUpDataBase(IServiceCollection services)
{
// here is where I use the InMemoryDatabase
}
}
测试服务器夹具:
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 testServerFixture 和 ITestOutputHelper 输出的 Iod 不起作用。如何让它发挥作用?
我查看了您的代码,经过一些研究后我得出结论,通过构造函数注入将 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;
}
//...
感谢@Nkosi 的帮助,它帮助我找到了解决方案:)。 我也受到了其他网站的启发:
- https://andrewlock.net/converting-integration-tests-to-net-core-3/
- https://gunnarpeipman.com/aspnet-core-integration-test-startup/
我也在我的 repo 上更新了解决方案
以下是重要部分:
测试服务器夹具:
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();
}
[...]
}
如果您有任何改进代码的建议或问题,请告诉我:)