Entity Framework Core 2.2 не сбрасывается после разрыва во время модульного тестирования - PullRequest
1 голос
/ 02 мая 2019

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

По сути, происходит то, что значения идентификаторов для объектов, которые высеваются, не сбрасываются после каждого теста.

В MSTestЯ реализовал настройку для создания нового контекста базы данных для каждого теста, предоставляя новое имя для каждого запуска теста, и я обязательно вызову EnsureCreated() перед заполнением моей базы данных.Кроме того, я также реализую TearDown для обеспечения правильного размещения базы данных.

[TestClass]
public class CountryTests
{
    private CdiContext Context { get; set; }

    [TestInitialize]
    public void Setup()
    {
        DbContextOptions<CdiContext> options = new DbContextOptionsBuilder<CdiContext>()
            .UseInMemoryDatabase(databaseName: $"{Guid.NewGuid()}")
            .Options;

        Context = new CdiContext(options);
        Context.Database.EnsureCreated();
        Seed();
    }

    [TestCleanup]
    public void TearDown()
    {
        Context.Database.EnsureDeleted();
    }

    private void Seed()
    {
        var service = new CoreDataService(Context);

        var regions = new List<Region>
        {
            new Region
            {
                Name = "Asia",
                State = RecordState.Active,
                Created = DateTime.Now,
                UserId = Guid.NewGuid().ToString()
            },

            new Region
            {
                Name = "Africa",
                State = RecordState.Active,
                Created = DateTime.Now,
                UserId = Guid.NewGuid().ToString()
            },

            new Region
            {
                Name = "South America",
                State = RecordState.Active,
                Created = DateTime.Now,
                UserId = Guid.NewGuid().ToString()
            }
        };

        Context.Regions.AddRange(regions);
        Context.SaveChanges();
    }

    [TestMethod]
    public async Task CanAddCountry()
    {
        //-- arrange
        var service = new CoreDataService(Context);

        var userId = "133BC82D-FDE2-4124-9207-CD3465511AEB";
        var region = await service.GetRegionById(1);

        var country = new Country
        {
            Name = "Canada",
            State = RecordState.Active,
            UserId = userId,
            Created = DateTime.Now,
            RegionId = region.Id
        };

        //-- act
        var results = await service.AddCountry(country);

        //-- assert
        Assert.IsTrue(results.Name == "Canada");
        Assert.IsTrue(results.UserId == "133BC82D-FDE2-4124-9207-CD3465511AEB");
        Assert.IsNotNull(results.Region);
    }

    [TestMethod]
    public async Task CanGetCountries()
    {
        //-- arrange
        var service = new CoreDataService(Context);

        var userId = "133BC82D-FDE2-4124-9207-CD3465511AEB";
        var region = service.GetRegionById(1);
        var names = new[] {"Canada", "Wales", "Japan", "Australia", "Hawaii", "Germany"};

        for (var x = 0; x < 5; x++)
        {
            await service.AddCountry(new Country
            {
                Name = names[x],
                State = RecordState.Active,
                UserId = userId,
                Created = DateTime.Now,
                RegionId = region.Id
            });
        }

        //-- act
        var results = await service.GetCountries();

        //-- assert
        Assert.IsNotNull(results);
        Assert.IsTrue(results.Count == 5);
    }

    [TestMethod]
    public async Task CanDeleteCountry()
    {
        //-- arrange
        var service = new CoreDataService(Context);

        var userId = "133BC82D-FDE2-4124-9207-CD3465511AEB";
        var region = service.GetRegionById(1);
        var names = new[] { "Canada", "Wales", "Japan", "Australia", "Hawaii", "Germany" };

        for (var x = 0; x < 5; x++)
        {
            await service.AddCountry(new Country
            {
                Name = names[x],
                State = RecordState.Active,
                UserId = userId,
                Created = DateTime.Now,
                RegionId = region.Id
            });
        }

        //-- act
        await service.DeleteCountry(id: 2, userId: Guid.NewGuid().ToString());

        var countries = await service.GetCountries();
        var country = await service.GetCountryById(2);

        //-- assert
        Assert.IsTrue(countries.Count != 5);
        Assert.IsNull(country);
    }
}

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

Сначала я думал, что это проблема с MSTest, но заметил такое же поведение и в xUnit.

public class CdiTestBase : IDisposable
{
    protected readonly CdiContext _context;

    public CdiTestBase()
    {
        var options = new DbContextOptionsBuilder<CdiContext>()
            .UseInMemoryDatabase(databaseName: $"{Guid.NewGuid()}")
            .Options;

        _context = new CdiContext(options);

        _context.Database.EnsureCreated();

        SeedRegions(_context);
    }

    public void Dispose()
    {
        _context.Database.EnsureDeleted();

        _context.Dispose();
    }

    private void SeedRegions(CdiContext context)
    {
        var regions = new List<Region>
        {
            new Region
            {
                Name = "Asia",
                State = RecordState.Active,
                Created = DateTime.Now,
                UserId = Guid.NewGuid().ToString()
            },

            new Region
            {
                Name = "Africa",
                State = RecordState.Active,
                Created = DateTime.Now,
                UserId = Guid.NewGuid().ToString()
            },

            new Region
            {
                Name = "South America",
                State = RecordState.Active,
                Created = DateTime.Now,
                UserId = Guid.NewGuid().ToString()
            }
        };

        context.Regions.AddRange(regions);
        context.SaveChanges();
    }
}

public class CountryTests : CdiTestBase
{
    [Fact]
    public async Task CanAddCountry()
    {
        //-- arrange
        var service = new CoreDataService(_context);

        var userId = "133BC82D-FDE2-4124-9207-CD3465511AEB";
        var region = await service.GetRegionById(1);

        var country = new Country
        {
            Name = "Canada",
            State = RecordState.Active,
            UserId = userId,
            Created = DateTime.Now,
            RegionId = region.Id
        };

        //-- act
        var results = await service.AddCountry(country);

        //-- assert
        Assert.True(results.Name == "Canada");
        Assert.True(results.UserId == "133BC82D-FDE2-4124-9207-CD3465511AEB");
        Assert.NotNull(results.Region);
    }

    [Fact]
    public async Task CanGetCountries()
    {
        //-- arrange
        var service = new CoreDataService(_context);

        var userId = "133BC82D-FDE2-4124-9207-CD3465511AEB";
        var region = service.GetRegionById(1);
        var names = new[] { "Canada", "Wales", "Japan", "Australia", "Hawaii", "Germany" };

        for (var x = 0; x < 5; x++)
        {
            await service.AddCountry(new Country
            {
                Name = names[x],
                State = RecordState.Active,
                UserId = userId,
                Created = DateTime.Now,
                RegionId = region.Id
            });
        }

        //-- act
        var results = await service.GetCountries();

        //-- assert
        Assert.NotNull(results);
        Assert.True(results.Count == 5);
    }

    [Fact]
    public async Task CanDeleteCountry()
    {
        //-- arrange
        var service = new CoreDataService(_context);

        var userId = "133BC82D-FDE2-4124-9207-CD3465511AEB";
        var region = service.GetRegionById(1);
        var names = new[] { "Canada", "Wales", "Japan", "Australia", "Hawaii", "Germany" };

        for (var x = 0; x < 5; x++)
        {
            await service.AddCountry(new Country
            {
                Name = names[x],
                State = RecordState.Active,
                UserId = userId,
                Created = DateTime.Now,
                RegionId = region.Id
            });
        }

        //-- act
        await service.DeleteCountry(id: 2, userId: Guid.NewGuid().ToString());

        var countries = await service.GetCountries();
        var country = await service.GetCountryById(2);

        //-- assert
        Assert.True(countries.Count != 5);
        Assert.Null(country);
    }
}

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

1 Ответ

3 голосов
/ 02 мая 2019

Это известная проблема с автоматически генерируемыми ключами в памяти, отслеживаемыми # 6872 InMemory: улучшена генерация ключей в памяти .

Это было исправлено в следующей версии 3.0 - Каждое свойство использует независимую генерацию целочисленных ключей в памяти :

Старое поведение

До выхода EF Core 3.0 один генератор общих значений использовался для всех свойств целочисленных ключей в памяти.

Новое поведение

Начиная с EF Core 3.0, каждое свойство целочисленного ключа получает свой собственный генератор значений при использовании базы данных в памяти. Также, если база данных удалена, генерация ключей сбрасывается для всех таблиц.

Почему

Это изменение было сделано для более точного согласования генерации ключей в памяти с реальной генерацией ключей базы данных и улучшения способности изолировать тесты друг от друга при использовании базы данных в памяти.

В настоящее время вы ничего не можете сделать, кроме как обновить тестовый код, чтобы не полагаться на жестко закодированные автоматически сгенерированные значения (что в любом случае не годится).

...