Заполнить тестовые данные для каждого теста в интеграционных тестах ASP.NET Core / EF Core / xUnit.NET - PullRequest
1 голос
/ 23 апреля 2019

Я следовал стратегиям настройки тестов для API ASP.NET Core 2.2 с использованием документации Microsoft по адресу Интеграционные тесты в ASP.NET Core .

Подводя итог,мы расширяем и настраиваем WebApplicationFactory и используем IWebHostBuilder для установки и настройки различных служб, чтобы предоставить нам контекст базы данных, используя базу данных в памяти для тестирования, как показано ниже (скопировано и вставлено из статьи):

public class CustomWebApplicationFactory<TStartup> 
    : WebApplicationFactory<TStartup> where TStartup: class
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureServices(services =>
        {
            // Create a new service provider.
            var serviceProvider = new ServiceCollection()
                .AddEntityFrameworkInMemoryDatabase()
                .BuildServiceProvider();

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

            // Build the service provider.
            var sp = services.BuildServiceProvider();

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

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

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

В тестах мы можем использовать фабрику и создать клиента следующим образом:

public class IndexPageTests : 
    IClassFixture<CustomWebApplicationFactory<RazorPagesProject.Startup>>
{
    private readonly HttpClient _client;
    private readonly CustomWebApplicationFactory<RazorPagesProject.Startup> 
        _factory;

    public IndexPageTests(
        CustomWebApplicationFactory<RazorPagesProject.Startup> factory)
    {
        _factory = factory;
        _client = factory.CreateClient(new WebApplicationFactoryClientOptions
            {
                AllowAutoRedirect = false
            });
    }

    [Fact]
    public async Task Test1()
    {
        var response = await _client.GetAsync("/api/someendpoint");
    }
}

Это работает нормально, но обратите внимание на вызов InitializeDbForTests, который устанавливает некоторые тестовые данные для всех тестов, когдаслужбы настроены.

Я бы хотел разумную стратегию для запуска каждого теста API с чистого листа, чтобы тесты не зависели друг от друга.Я искал различные способы овладеть ApplicationDbContext в моих методах испытаний, но безрезультатно.

Было бы разумно проводить интеграционные тесты в полной изоляции друг от друга, и как я мог подойтиэто с помощью ASP.NET Core / EF Core / xUnit.NET?

Ответы [ 2 ]

0 голосов
/ 25 апреля 2019

На самом деле, Тестирование с помощью InMemory действительно хорошо описывает процесс в разделе «Написание тестов». Вот код, который иллюстрирует основную идею

    [TestClass]
public class BlogServiceTests
{
    [TestMethod]
    public void Add_writes_to_database()
    {
        var options = new DbContextOptionsBuilder<BloggingContext>()
            .UseInMemoryDatabase(databaseName: "Add_writes_to_database")
            .Options;

Идея состоит в том, что для каждого метода тестирования существует отдельная база данных, поэтому вам не нужно беспокоиться о порядке выполнения тестов или о том, что они выполняются параллельно. Конечно, вам придется добавить некоторый код, который заполняет вашу базу данных, и вызывать его из каждого метода тестирования.

Я использовал эту технику, и она работает довольно хорошо.

0 голосов
/ 23 апреля 2019

Как ни странно, вы ищете EnsureDeleted вместо EnsureCreated. Это сбросит базу данных. Поскольку «база данных» в памяти не имеет схемы, вам на самом деле не нужно гарантировать, что она создана, или даже перенести ее.

Кроме того, вы не должны использовать жестко запрограммированное имя для базы данных в памяти. Это фактически приведет к тому, что один и тот же экземпляр базы данных в памяти будет использоваться везде. Вместо этого вы должны использовать что-то случайное: Guid.NewGuid().ToString() достаточно хорошо.

...