【问题标题】:Two different EF dbContexts are not working in same unit test两个不同的 EF dbContexts 不在同一个单元测试中工作
【发布时间】:2018-05-18 14:06:02
【问题描述】:

我正在使用: 英孚 6.2, 视觉工作室 2017, nUnit 2.6.3.13283(单元测试), Unity 5.8.5(作为 IoC)。

当我想在同一个 UnitTest 中测试两个不同的 DbContext 时出现问题。

第一个上下文:

public class MsSqlConfiguration : System.Data.Entity.DbConfiguration
{
    public MsSqlConfiguration()
    {
        this.SetDefaultConnectionFactory(new System.Data.Entity.Infrastructure.SqlConnectionFactory());
        this.SetProviderServices("System.Data.SqlClient", System.Data.Entity.SqlServer.SqlProviderServices.Instance);
    }
}

[DbConfigurationType(typeof(MsSqlConfiguration))]
public class SqlDbContext: DbContext
{
    public SqlDbContext(string connectonString) : base(connectonString)
    {}
    public DbSet<SomeClass> SomeField { get; set; }
}

第二个背景:

public class SQLiteProviderInvariantName : IProviderInvariantName
{
    public static readonly SQLiteProviderInvariantName Instance = new SQLiteProviderInvariantName();
    private SQLiteProviderInvariantName() { }
    public const string ProviderName = "System.Data.SQLite.EF6";
    public string Name { get { return ProviderName; } }
}

class SQLiteDbDependencyResolver : IDbDependencyResolver
{
    public object GetService(Type type, object key)
    {
        if (type == typeof(IProviderInvariantName)) return SQLiteProviderInvariantName.Instance;
        if (type == typeof(DbProviderFactory)) return SQLiteProviderFactory.Instance;
        return SQLiteProviderFactory.Instance.GetService(type);
    }

    public IEnumerable<object> GetServices(Type type, object key)
    {
        var service = GetService(type, key);
        if (service != null) yield return service;
    }
}

public class SQLiteConfiguration : System.Data.Entity.DbConfiguration
{
    public SQLiteConfiguration()
    {
        AddDependencyResolver(new SQLiteDbDependencyResolver());
        SetProviderFactory("System.Data.SQLite", SQLiteFactory.Instance);
        SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance);
        SetProviderServices("System.Data.SQLite", (DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices)));
    }
}

[DbConfigurationType(typeof(SQLiteConfiguration))]
public class SqlDbContext : DbContext
{
    public SqlDbContext (string connectonString) : base(connectonString)
    {
    }

    public DbSet<SomeClass> SomeField{ get; set; }
}

单元测试:

[TestFixture]
class DbContextIntegrationTests
{
    [Test]
    public void CanReadFromMsSqlDatabase()
    {
        using (var context = IocContainer.Instance.Resolve<MsSqlDbContext>(someConnString))
        {
            Assert.DoesNotThrow(() => context.SomeField.FirstOrDefault());
        }
    }

    [Test]
    public void CanReadFromSqliteDatabase()
    {
        using (var context2 = IocContainer.Instance.Resolve<SqliteDbContext>(someConnString2))
        {
            Assert.DoesNotThrow(() => context2.Somefield.FirstOrDefault());
        }
    }
}

当我通过传递连接字符串分别实例化上述上下文时 - 它们都可以正常工作。

但是,如果它们是同一个单元测试类的一部分 - 它们将无法运行。 第一个上下文将它的提供程序设置为默认值(比如说 SQL 一个),而下一个 DbContext(比如说 SQLite 一个)不能设置它的提供程序。

如果 MS SQL dbcontext 先出现,则 SQLite dbcontext 获取下一个异常:

System.InvalidOperationException: '无法完成操作。这 提供的 SqlConnection 未指定初始目录或 附加数据库文件名。'

如果 SQLite 先行,则 MS SQL 上下文获取:

System.InvalidOperationException: '在 SQLite 提供程序清单中找不到存储类型'date''

我只是想知道我在这里缺少什么。 是否是 nUnit 特定的(一些缓存)。 或者它确实是 EF 提供程序的一些常见位置,只能设置一次。

我根本没有使用 App.config - 只是从某个保存的地方传递配置字符串。

【问题讨论】:

  • 你能不能添加你得到的异常,如果你添加单元测试代码会很糟糕
  • 同名项目中真的有两个不同的Context吗?
  • @programtreasures 我添加了例外。
  • @Bit 是的。我用两种不同的方法创建 dbcontexts 并洞察“使用”。
  • @VadymK 如果它是相同的架构,那么我不会复制代码,如果它是不同的架构,那么您可能想要更改名称并在每个 modelBuilder.HasDefaultSchema("")

标签: c# entity-framework nunit unity-container


【解决方案1】:

@Bit @programtreasures

找到了答案。 根本原因是 EF 无法同时处理多个 DBConfiguration(可能在内存中),即使它们是不同 DbContext 的一部分。

更多细节在这里: https://msdn.microsoft.com/en-us/data/jj680699

所以我刚刚创建了一个通用上下文:

using System.Data.Entity.Core.Common;
using System.Data.SQLite;
using System.Data.SQLite.EF6;

namespace ClassLibrary1
{
    public class commonConfig : System.Data.Entity.DbConfiguration
    {
        public commonConfig()
        {
            SetDefaultConnectionFactory(new System.Data.Entity.Infrastructure.SqlConnectionFactory());
            SetProviderServices("System.Data.SqlClient", System.Data.Entity.SqlServer.SqlProviderServices.Instance);

            SetProviderFactory("System.Data.SQLite", SQLiteFactory.Instance);
            SetProviderServices("System.Data.SQLite", (DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices)));
            SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance);
        }
    }
}

和 MS SQL DB 上下文:

using System.Data.Entity;
using System.Data.SqlClient;

namespace ClassLibrary1
{
    [DbConfigurationType(typeof(commonConfig))]
    public class MsSqlDbContext : DbContext
    {
        public MsSqlDbContext(SqlConnection existingConnection,
                                 bool contextOwnsConnection) : base(existingConnection, contextOwnsConnection)
        {
            DbConfiguration.SetConfiguration(new commonConfig());
        }

        public DbSet<SomeTableEntity> SomeTable { get; set; }
    }
}

还有 SqliteDbContext:

using System.Data.Entity;
using System.Data.SQLite;

namespace ClassLibrary1
{
    [DbConfigurationType(typeof(commonConfig))]
    public class SqliteDbContext : DbContext
    {
        public SqliteDbContext(SQLiteConnection existingConnection,
                            bool contextOwnsConnection) : base(existingConnection, contextOwnsConnection)
        {
            DbConfiguration.SetConfiguration(new commonConfig());
        }

        public DbSet<SomeDbTableEntity> SomeTable { get; set; }
    }
}

然后我可以像下面这样运行单元测试:

[TestMethod]
public void TestMethod()
{
    using (var context1 = new SqliteDbContext(new SQLiteConnection(
            @"C:\db.sqlite"), true
    ))
    {
        Console.WriteLine("SQLITE" + Environment.NewLine);
        Console.Write(context1.SomeTable.FirstOrDefault().SomeRecord);
        Console.WriteLine(Environment.NewLine);
    }

    using (var context2 =

        new MsSqlDbContext(
            new SqlConnection(@"Data Source=localhost;Initial Catalog=SomeDatabase;Integrated Security=True")
            , true)

        )
    {
        Console.WriteLine("MS SQL" + Environment.NewLine);
        Console.Write(context2.SomeTable.FirstOrDefault().SomeRecord);
        Console.WriteLine(Environment.NewLine);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-13
    • 1970-01-01
    • 2022-11-14
    • 2017-07-07
    • 1970-01-01
    • 1970-01-01
    • 2020-01-23
    相关资源
    最近更新 更多