在某些测试中,如何覆盖使用IWebHostBuilder.ConfigureTestServices模拟的服务

时间:2019-10-27 04:30:32

标签: c# asp.net-core .net-core integration-testing

我有一个自定义WebApplicationFactory<Startup>,我模拟了一些用于集成测试的服务,例如DatabaseSeeder,以使测试运行更快。

现在,我想测试数据库种子,因此我想覆盖此配置以使用真正的数据库种子来进行此测试。

我尝试使用WithWebHostBuilder,它返回一个新的WebApplicationFactory<Startup>,但是此新工厂中的builder.ConfigureTestServices方法在原始工厂之前运行,因此它被原始工厂ConfigureTestServices覆盖

  /// <summary>
    /// custom web application factory for testing.
    /// </summary>
    public class LwtTestWebApplicationFactory : WebApplicationFactory<Startup>
    {
        ....

        /// <inheritdoc />
        protected override void ConfigureWebHost(IWebHostBuilder builder)
        {
            builder.ConfigureTestServices(
                services =>
                {
                    // Replace database seeder.
                    ServiceDescriptor databaseSeederDescriptor =
                        services.Single(s => s.ServiceType == typeof(IDatabaseSeeder));

                    services.Remove(databaseSeederDescriptor);

                    var mock = new Mock<IDatabaseSeeder>();
                    mock.Setup(s => s.SeedData())
                        .Returns(Task.CompletedTask);
                    services.AddTransient(resolver => mock.Object);

                    // Replace index creator.
                    ServiceDescriptor indexCreatorDescriptor =
                        services.Single(s => s.ServiceType == typeof(IIndexCreator));

                    services.Remove(indexCreatorDescriptor);

                    var indexCreatorMock = new Mock<IIndexCreator>();
                    indexCreatorMock.Setup(s => s.CreateIndexesAsync())
                        .Returns(Task.CompletedTask);
                    services.AddTransient(resolver => indexCreatorMock.Object);

                    // Remove the app's ApplicationDbContext registration.
                    ServiceDescriptor descriptor = services.SingleOrDefault(
                        d => d.ServiceType == typeof(DbContextOptions<IdentityDbContext>));

                    if (descriptor != null)
                    {
                        services.Remove(descriptor);
                    }

                    // Add ApplicationDbContext using an in-memory database for testing.
                    services.AddDbContext<IdentityDbContext>(
                        (options, context) => { context.UseInMemoryDatabase("InMemoryDbForTesting"); });

                    ServiceDescriptor appSettingDescriptor = services.SingleOrDefault(
                        d => d.ServiceType == typeof(AppSettings));

                    if (appSettingDescriptor != null)
                    {
                        var appSetting = (AppSettings)appSettingDescriptor.ImplementationInstance;
                        services.Remove(appSettingDescriptor);
                        services.AddSingleton(
                            new AppSettings
                            {
                                MongoDatabase = appSetting.MongoDatabase,
                                Secret = appSetting.Secret,
                                MongoConnectionString = this.mongoDbRunner.ConnectionString,
                            });
                    }
                });
        }

        .....
    }
}

我尝试过的事情。

    using (var factory = new LwtTestWebApplicationFactory())
    using (WebApplicationFactory<Startup> seedEnabledFactory = factory.WithWebHostBuilder(
                builder =>
                {
                    builder.ConfigureTestServices(
                        services =>
                        {
                            // Replace database seeder.
                            ServiceDescriptor databaseSeederDescriptor =
                                services.Single(s => s.ServiceType == typeof(IDatabaseSeeder));

                            services.Remove(databaseSeederDescriptor);

                            services.AddTransient<IDatabaseSeeder, DatabaseSeeder>();

                            // Replace index creator.
                            ServiceDescriptor indexCreatorDescriptor =
                                services.Single(s => s.ServiceType == typeof(IIndexCreator));

                            services.Remove(indexCreatorDescriptor);

                            services.AddTransient<IIndexCreator, MongoDbIndexCreator>();
                        });
                }))

1 个答案:

答案 0 :(得分:0)

我有相同的任务-理想情况下,以一种测试方法在本地重写某些服务,而不必每次都重新构建容器:

[Fact]
public async Task GetSampleValue_WhenCalledWithMock_ReturnsMockValue()
{
    using var mockServiceScope = _testHostServiceProvider.CreateScope(mockServices =>
    {
        var mockSampleService = Substitute.For<ISampleService>();
        mockSampleService.GetSampleValue().ReturnsForAnyArgs("Mock value");
        mockServices.AddSingleton(_ => mockSampleService);
    });
    var sampleController = RestClient.For<ISampleController>(_testHost.HttpClient);

    var sampleValue = await sampleController.GetSampleValue();
    Assert.Equal("Mock value", sampleValue);
}

我在库Rsi.DependencyInjection中实现了此功能。也许会对您有所帮助。