Получение ASP. NET контекста базы данных Core 3.1 в интеграционном тесте Xunit - PullRequest
2 голосов
/ 27 мая 2020

Я создавал интеграционные тесты с использованием Xunit для веб-приложения. NET Core 3.1, которое использует базу данных. Для тестирования я переключился на базу данных в памяти, следуя документации Microsoft . Код CustomWebApplicationFactory :

public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
        {
        protected override void ConfigureWebHost(IWebHostBuilder webHostBuilder)
            {
            webHostBuilder.ConfigureServices(services =>
                {
                    // Remove the app's database  registration.
                    var serviceDescriptor = services
                                                .SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<MyDbContext>));

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

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

                    var servicesProvider = services.BuildServiceProvider();

                    // Create a scope to obtain a reference to the database context (MyDbContext).
                    using (var serviceScope = servicesProvider.CreateScope())
                        {
                        var scopedServices = serviceScope.ServiceProvider;
                        var db = scopedServices.GetRequiredService<MyDbContext>();
                        var logger = scopedServices.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();

                        db.Database.EnsureCreated();                                                                                                                                         // Ensure the database is created.

                        try
                            {
                            DatabaseSeeding.voidInitialiseCazIdentityProviderDatabase(db);                                                                                                                              // Seed the database with test data.
                            }
                        catch (Exception ex)
                            {
                            logger.LogError(ex, $"An error occurred seeding the database with data. Error: {ex.Message}");
                            }
                        }
                });
            }

Мои тесты страниц basi c отлично работают с этим расположением, но теперь я хочу проверить, была ли исправлена ​​база данных в памяти изменено интеграционным тестом. Что бы ни случилось, ссылка на базу данных не попадает в контейнер Xunit DI (если такая вещь существует). Мой тестовый класс инициализируется следующим кодом:

    public class IdpUserServiceTests : IClassFixture<CustomWebApplicationFactory<Startup>>
    {
    private readonly CustomWebApplicationFactory<Startup> _webApplicationFactory;
    private readonly ITestOutputHelper _testOutput;
    private readonly HttpClient _httpClient;
    private readonly MyDbContext _myDbContext;

    public IdpUserServiceTests(CustomWebApplicationFactory<Startup> webApplicationFactory, MyDbContext myDbContext, ITestOutputHelper testOutput)
        {
        _webApplicationFactory = webApplicationFactory;
        _myDbContext = myDbContext;
        _testOutput = testOutput;
        _httpClient = _webApplicationFactory.CreateClient();
        }

    //Tests 

, но при попытке запустить тест я получаю следующую ошибку:

The following constructor parameters did not have matching fixture data: MyDbContext objMyDbContext

Я ищу правильный путь для доступа к базе данных в памяти - очевидно, не через внедрение конструктора. У меня был go с этим ответом - Доступ к dbcontext в памяти в интеграционном тесте - но, похоже, все изменилось между 2.2 и 3.1.

1 Ответ

1 голос
/ 26 июня 2020

Оказалось, что Доступ к dbcontext в памяти в интеграционном тесте , упомянутый выше, не совсем подходит для ASP. NET Core 3.1 . scopeFactory нужно найти из другого источника:

var scopeFactory = _webApplicationFactory.Services.GetService<IServiceScopeFactory>();

Итак, теперь тестовый класс выглядит так:

public class ServiceTests : IClassFixture<CustomWebApplicationFactory<Startup>>
    {
    private readonly CustomWebApplicationFactory<Startup> _webApplicationFactory;
    private readonly ITestOutputHelper _testOutput;
    private readonly HttpClient _httpClient;

    public ServiceTests(CustomWebApplicationFactory<Startup> webApplicationFactory, ITestOutputHelper testOutput)
        {
        _webApplicationFactory = webApplicationFactory;
        _testOutput = testOutput;
        _httpClient = _webApplicationFactory.CreateClient();
        }

    [Fact]

    public async Task AServiceTest()
        {
        // Do some HTTP client stuff that alters the in-memory database

      var scopeFactory = _webApplicationFactory.Services.GetService<IServiceScopeFactory>();

        using(var scope = scopeFactory.CreateScope())
            {
            var myDataContext = scope.ServiceProvider.GetService<MyDataContext>();

            // Query the in-memory database
            }
        }
    }
...