Entity Framework Core 2.2 在单元测试时拆卸后未重置

Entity Framework Core 2.2 not reseting after tear down while unit testing

我正在尝试编写一些单元测试来尽可能多地覆盖我的 api,但我决定使用 InMemory 提供程序而不是使用数据库,而不是测试 EF 是否有效, 而不是我的植入是正确的,但我 运行 正在进入的是一个奇怪的副作用。

基本上发生的是被播种的对象的 id 值,不会在每次测试后重置。

在 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);
    }
}

现在当我运行这个的时候,第三个测试失败了,因为它找不到正确的id,这对我来说有点奇怪。

我最初认为这是 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);
    }
}

如果我 运行 同时进行所有测试,我总是会失败,但如果我 运行 每个测试单独进行,它们都会通过,这让我很困扰。

这是内存数据库自动生成密钥的一个已知问题,由 #6872 InMemory: Improve in-memory key generation 跟踪。

已在即将发布的 3.0 版本中修复 - Each property uses independent in-memory integer key generation:

Old behavior

Before EF Core 3.0, one shared value generator was used for all in-memory integer key properties.

New behavior

Starting with EF Core 3.0, each integer key property gets its own value generator when using the in-memory database. Also, if the database is deleted, then key generation is reset for all tables.

Why

This change was made to align in-memory key generation more closely to real database key generation and to improve the ability to isolate tests from each other when using the in-memory database.

除了更新测试代码以不依赖硬编码自动生成的值(无论如何这都不好)之外,您目前无能为力。