在 Visual Studio 中针对多个配置运行单个测试

Ank*_*jay 7 c# integration-testing xunit .net-core asp.net-core

我们使用在 ASP.NET Core 2.2 上运行的 Web API设置集成测试xUnitMicrosoft.AspNetCore.TestHost.TestServer运行测试。

我们的 Web API 是一个单一的代码库,可以根据一些配置或应用程序设置差异(如国家货币等)单独部署多次。

下图试图解释我们的部署设置:

在此处输入图片说明

我们希望确保我们的集成测试针对所有部署运行。

对于这两种部署,XX` API 端点、请求和响应完全相同。因此,当涉及到每个部署的集成测试时,我们希望避免重复自己。

以下是解释我们当前测试设置的示例代码:

TestStartup.cs

public class TestStartup : IStartup
{
    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
       var configuration = new ConfigurationBuilder()
           .SetBasePath(Directory.GetCurrentDirectory())
           .AddJsonFile("appsettings.json", false)
           .AddEnvironmentVariables()
           .Build();

        services.AddMvc()
            .SetCompatibilityVersion(version: CompatibilityVersion.Version_2_2);

        // Code to add required services based on configuration


        return services.BuildServiceProvider();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseMvc();

        // Code to configure test Startup
    }
}
Run Code Online (Sandbox Code Playgroud)

TestServerFixture.cs

public class TestServerFixture
{

    public TestServerFixture()
    {
        var builder = new WebHostBuilder().ConfigureServices(services =>
        {
            services.AddSingleton<IStartup>(new TestStartup());
        });

        var server = new TestServer(builder);
        Client = server.CreateClient();
    }

    public HttpClient Client { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)

MyTest.cs

public class MyTest : IClassFixture<TestServerFixture>
{
    private readonly TestServerFixture _fixture;

    public MyTest(TestServerFixture fixture)
    {
        _fixture = fixture;
    }

    [Fact]
    public void ItShouldExecuteTwice_AgainstTwoSeparateConfigurations()
    {
        //...
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我希望ItShouldExecuteTwice_AgainstTwoSeparateConfigurations在课堂上MyTest针对两种不同的配置/应用设置或换句话说针对 Visual Studio 中的两种不同测试部署在课堂上运行测试不止一次。

  • 我知道,我应该能够使用构建配置(如DEBUG_SETTING1, DEBUG_SETTING2)和预处理器指令(#if DEBUG_SETTING1)的组合来实现这一点。

  • 另一种选择可能是拥有一个带有通用方法的基本测试帮助程序项目和每个部署的单独集成项目。

有没有更好,更优雅的方法来实现这一目标?

Nko*_*osi 5

重构测试启动以允许根据测试需要对其进行修改

例如

public class TestStartup : IStartup {
    private readonly string settings;

    public TestStartup(string settings) {
        this.settings = settings;
    }

    public void ConfigureServices(IServiceCollection services) {
       var configuration = new ConfigurationBuilder()
           .SetBasePath(Directory.GetCurrentDirectory())
           .AddJsonFile(settings, false) //<--just an example
           .AddEnvironmentVariables()
           .Build();

        services.AddMvc()
            .SetCompatibilityVersion(version: CompatibilityVersion.Version_2_2);

        //...Code to add required services based on configuration

    }

    public void Configure(IApplicationBuilder app) {
        app.UseMvc();

        //...Code to configure test Startup
    }
}
Run Code Online (Sandbox Code Playgroud)

并通过夹具过滤该图案

public class TestServerFixture {
    static readonly Dictionary<string, TestServer> cache = 
        new Dictionary<string, TestServer>();

    public TestServerFixture() {
        //...
    }

    public HttpClient GetClient(string settings) {
        TestServer server = null;
        if(!cache.TryGetValue(settings, out server)) {
            var startup = new TestStartup(settings); //<---
            var builder = new WebHostBuilder()
                .ConfigureServices(services => {
                    services.AddSingleton<IStartup>(startup);
                });
            server = new TestServer(builder);
            cache.Add(settings, server);
        }
        return server.CreateClient();
    }
}
Run Code Online (Sandbox Code Playgroud)

最终测试本身

public class MyTest : IClassFixture<TestServerFixture> {
    private readonly TestServerFixture fixture;

    public MyTest(TestServerFixture fixture) {
        this.fixture = fixture;
    }

    [Theory]
    [InlineData("settings1.json")]
    [InlineData("settings2.json")]
    public async Task Should_Execute_Using_Configurations(string settings) {
        var client = fixture.CreateClient(settings);

        //...use client

    }
}
Run Code Online (Sandbox Code Playgroud)