c# - Entity Framework Core 2.2 在单元测试时拆除后不重置

标签 c# entity-framework-core mstest xunit

我正在尝试编写一些单元测试以尽可能多地覆盖我的 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);
    }
}

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

最佳答案

这是内存数据库自动生成 key 的一个已知问题,由 #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.

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

关于c# - Entity Framework Core 2.2 在单元测试时拆除后不重置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55952419/

相关文章:

c# - 使用 IMAP 计算 gmail 中的电子邮件数量

c# - 结合 join 和 group by 时,EF Core 3.1 意外生成 SQL

c# - 在 Asp.net Core 2.2 和 Entity Framework Core 中,数据库架构在运行时不会更改

.net - 在编码 UI 中与应用程序的多个实例交互

c# - 在我们的服务器之间强制执行 TLS 1.2 后,Web Api 调用现在失败

c# - 将不同的模型类型从 Controller 传递到 View 是好的做法吗?

c# - AluminiumLua定义lua函数

c# - MySqlException : Data too long for column 'Id' at row 1

.net - NUnit 多个 TestFixture 等效于 MsTest

command-line - MSTest.exe 没有复制所有需要的项目 DLL?