Testing eager-loading scenarios with Effort.EF6


Question

We're using Effort.EF6 to build a test suite for an ASP.NET Web API 2 service working against an in-memory database, and for the most part it's a wonderful experience.

However, for reasons unrelated to this question, we have had to turn off lazy loading in EF6 (by running Configuration.LazyLoadingEnabled = false; in the constructor of the db context), which means that if we forget to .Include() a relation somewhere and later use it, we get NullReferenceExceptions. We'd like our tests to catch these types of errors.

Our test setup is basically as follows:

  1. Create a db connection using Effort's connection factories. This is a unique connection instance (with a unique key, when we try with persistent connections) per test.
  2. Create a db context with that connection, and add the data we want to exist for the test.
  3. Register a service override in the DI container for the db context.

The problem is we can't figure out how to configure Effort.EF6 to disallow lazy loading, since it seems that anything we've added to the context in our test setup is already loaded when the code under test runs, and thus we never see the exceptions. We're assuming this is because we're re-using the context instance between test setup and actual code execution.

If we try to switch the third step to the following:

  1. Register a service override in the DI container for the db connection.
  2. The DI container creates a db context instance (taking the db connection as an injected dependency)

we instead end up with an empty db context, i.e. it has no data despite us adding a few data points before running the test.

How can we construct and inject a db context using Effort, which will fail if the .Include() statement is missing but work if it's there?

Accepted Answer

You have to deactivate it in the constructor for Effort.EF6 too - the one that takes the DbConnection object.

I solved it for my EF Code First project like followed:

public class MyDataContext : DbContext, IMyDataContext
{
    /*
    * the ohter stuff like IDbSet<T> etc.
    */


    public MyDataContext() : base("name=MyConnectionString")
    {
        Configure();
    }

    /// <summary>
    /// This constructor is for test usage only!
    /// </summary>
    /// <param name="connection">Test connection for in memory database</param>
    public MyDataContext(DbConnection connection) : base(connection, true)
    {
        Configure();
    }


    /// <summary>
    /// Configures the data context.
    /// </summary>
    private void Configure()
    {
        Configuration.LazyLoadingEnabled = false;
    }
}

Furthermore in my test projects I am setting up test CSV files. The files will be used by Effort.EF6 to instantiate a context with seeded data. In my case I wrote a small TestDataManager that gives the possability to seed specific tables with specific files.

Here is a piece of code how you could seed data with Effort.EF6:

IDataLoader loader = new CsvDataLoader(@"C:\Temp\Test_CSV_Files");
DbConnection dbConnection = DbConnectionFactory.CreateTransient(loader);
var myDataContext = new MyDataContext(dbConnection);

Maybe this blog post could help you too.





Licensed under: CC-BY-SA
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why