XUnit测试的EF Core DbContext并发问题

时间:2019-05-26 08:28:39

标签: c# entity-framework-core xunit

我似乎有一个奇怪的并发问题,我似乎没办法动手。 当我构建DbContext的实现时,我注入了我想由modelbuilder构建的实体(不必担心为什么)。这仅由我的应用程序在运行时完成一次,并且运行良好,但是当我进行集成测试数据库集成时,我只注入了InMemoryDatabase所需的测试实体。

现在,我似乎遇到了一个奇怪的问题,即需要不同实体的不同类文件中的两个单元测试似乎交叉了。

我继续运行单元测试,第一个测试将通过,但是第二个测试将失败,因为该模型中不存在TestObjectB。当我检查模型时,它说存在TestObjectA,即使没有在该测试中注入它。好像DataContext的实现是静态的并且被覆盖了......这些是上下文的不同文件和新构造函数,我不明白它们是如何交叉路径的?如果我自己运行失败的单元测试,则测试通过。

请注意,以下代码已针对您的视图进行了简化。

数据库上下文:

public class DataContext : DbContext
{
    private readonly List<IEntity> _entities;

    public DataContextA(List<IEntity> entities, DbContextOptions options) : base(options)
    {
        _entities = entities;
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        foreach (var entity in _entities)
        {
            modelBuilder.Entity(entity.GetType());
        }
    }
}

测试实现1:

[Fact]
            public void CheckUniqueFieldA()
            {
                var options = new DbContextOptionsBuilder<DataContext>();

                options.UseInMemoryDatabase(Guid.NewGuid().ToString());

                using (var context = new DataContext(new List<IEntity> { new TestObjectA() }, options.Options))
                {
                    //Do Something
                }
            }

测试实施2:

[Fact]
            public void CheckUniqueFieldB()
            {
                var options = new DbContextOptionsBuilder<DataContext>();

                options.UseInMemoryDatabase(Guid.NewGuid().ToString());

                using (var context = new DataContext(new List<IEntity> { new TestObjectB() }, options.Options))
                {
                    //Do Something
                }
            }

1 个答案:

答案 0 :(得分:2)

原因是Alternating between multiple models with the same DbContext type文档主题中描述了EF Core模型缓存:

  

...模型缓存机制EF通过仅一次调用OnModelCreating并缓存模型来提高性能。

     

默认情况下,EF假定对于任何给定的上下文类型,模型都是相同的。

该链接还包含如何解决该问题的示例。您需要创建IModelCacheKeyFactory接口的自定义实现,并在ReplaceService中使用OnConfiguring替换默认的EF Core实现。实现应返回一个对象,该对象代表给定DbContext实例的唯一缓存键。默认实现只是返回context.GetType()