在 MSTest v2 中的并行测试之间共享 Entity Framework 核心数据库上下文

Share Entity Framework Core Database Context between parallel tests in MSTest v2

我正在尝试采用 this 通过使用 MSTest v2 的多个测试共享数据库连接,不幸的是它没有像 xUnit 这样的固定装置。因此我创建了一个静态 class:

[TestClass]
static class DbContextFactory
{
    private static string ConnectionString = "Server=(localdb)\MSSQLLocalDB;Initial Catalog=C4S_Test;ConnectRetryCount=0";

    /// <summary>
    /// Exposed connection for making shared transactions across multiple context instances possible
    /// </summary>
    public static DbConnection Connection;

    //called once before tests
    [AssemblyInitialize]
    public static void InitializeDbContext(TestContext context)
    {
        Connection = new SqlConnection(ConnectionString);
        Seed();
        Connection.Open();
    }

    public static C4S_DataContext CreateContext(DbTransaction transaction = null)
    {
        var context =
            new C4S_DataContext(new DbContextOptionsBuilder<C4S_DataContext>().UseSqlServer(Connection)
                .EnableSensitiveDataLogging().Options);

        if (transaction != null)
        {
            context.Database.UseTransaction(transaction);
        }

        return context;
    }

    [AssemblyCleanup]
    public static void Cleanup()
    {
        Connection.Close();
    }

    private static void Seed()
    {
        using (var context = CreateContext())
        {
            context.Database.EnsureDeleted();
            context.Database.EnsureCreated();

            //seed some data

            context.SaveChanges();
        }
    }

在测试中我使用 C4S_DataContext 如下:

using (var dbContext = DbContextFactory.CreateContext())
{
    //work on dbContext
}

运行 测试串行工作正常,但 运行 它们在以下异常中并行结束:

    Message: 
    Test method C4S.Model.Services.Tests.PortfolioGruppenServiceTests.GetPortfolioElementeInGruppeOrderedByBezeichnungAppTest threw exception: 
    System.InvalidOperationException: Internal connection fatal error.
  Stack Trace: 
    TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
    TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
    TdsParser.DrainData(TdsParserStateObject stateObj)
    TdsParser.ThrowUnsupportedCollationEncountered(TdsParserStateObject stateObj)
    TdsParser.GetCodePage(SqlCollation collation, TdsParserStateObject stateObj)
    TdsParser.TryCommonProcessMetaData(TdsParserStateObject stateObj, _SqlMetaData col)
    TdsParser.TryProcessMetaData(Int32 cColumns, TdsParserStateObject stateObj, _SqlMetaDataSet& metaData)
    TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
    SqlDataReader.TryConsumeMetaData()
    SqlDataReader.get_MetaData()
    SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
    SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
    SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite, String method)
    SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
    SqlCommand.ExecuteReader(CommandBehavior behavior)
    SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
    DbCommand.ExecuteReader()
    RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues)
    RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
    SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
    Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found)
    lambda_method(Closure )
    ResultEnumerable`1.GetEnumerator()
    LinqOperatorProvider._TrackEntities[TOut,TIn](IEnumerable`1 results, QueryContext queryContext, IList`1 entityTrackingInfos, IList`1 entityAccessors)+MoveNext()
    Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found)
    Enumerable.First[TSource](IEnumerable`1 source)
    <>c__DisplayClass15_1`1.<CompileQueryCore>b__0(QueryContext qc)
    QueryCompiler.Execute[TResult](Expression query)
    EntityQueryProvider.Execute[TResult](Expression expression)
    Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)

我假设存在并发问题,但无法解决。您还需要了解以下有关使用来自文档的打开连接的 EF 行为的信息:

connection DbConnection An existing DbConnection to be used to connect to the database. If the connection is in the open state then EF will not open or close the connection. If the connection is in the closed state then EF will open and close the connection as needed. Source

如上所述,根本不支持并发使用 SqlConnection GitHub