简体   繁体   中英

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

I'm trying to adopt this for sharing a database connection over multiple tests using MSTest v2 which unfortunately doesn't have Fixtures like xUnit. Therefore I created a static 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();
        }
    }

In the the tests I use the C4S_DataContext as follows:

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

Running tests serially works fine, but running them parallel ends in the following exception:

    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)

I assume a concurrency problem but can't figure it out. You also need to know the following about EF's behaviour using open connections from the docs:

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM