5

My question and code is based on the Code First Entity Framework Unit Test Examples blog post. I am using SQL Compact 4.0 and as such my unit tests are running against the actual database using real data similar to what is being described in the blog post.

I want to seed my production database with default values in some of the tables but when running my unit tests I want to add additional data and update some of the default values.

I have created a custom Initializer class that seeds the database with the default values. For my unit tests I have created another custom Initializer that inherits from the first one that does the test specific seeding and/or modifications:

public class NerdDinnersInitializer : DropCreateDatabaseIfModelChanges<NerdDinners>
{
    protected override void Seed(NerdDinners context)
    {
        var dinners = new List<Dinner>
                          {
                              new Dinner()
                                  {
                                      Title = "Dinner with the Queen",
                                      Address = "Buckingham Palace",
                                      EventDate = DateTime.Now,
                                      HostedBy = "Liz and Phil",
                                      Country = "England"
                                  }
                          };

        dinners.ForEach(d => context.Dinners.Add(d));

        context.SaveChanges();
    }
}

public class NerdDinnersInitializerForTesting : NerdDinnersInitializer
{
    protected override void Seed(NerdDinners context)
    {
        base.Seed(context);

        var dinner = context.Dinners.Where(d => d.Country == "England").Single();
        dinner.Country = "Ireland";

        context.SaveChanges();
    }
}

I also use a base class for my unit tests that initializes the test database like so:

[TestClass]
public abstract class TestBase
{
    protected const string DbFile = "test.sdf";
    protected const string Password = "1234567890";
    protected NerdDinners DataContext;

    [TestInitialize]
    public void InitTest()
    {
        Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0", "",
                string.Format("Data Source=\"{0}\";Password={1}", DbFile, Password));
        Database.SetInitializer(new NerdDinnersInitializerForTesting());

        DataContext = new NerdDinners();
        DataContext.Database.Initialize(true);
    }

    [TestCleanup]
    public void CleanupTest()
    {
        DataContext.Dispose();

        if (File.Exists(DbFile))
        {
            File.Delete(DbFile);
        }
    }
}

The actual unit test looks like this:

[TestClass]
public class UnitTest1 : TestBase
{
    [TestMethod]
    public void TestMethod1()
    {
        var dinner = new Dinner()
                          {
                              Title = "Dinner with Sam",
                              Address = "Home",
                              EventDate = DateTime.Now,
                              HostedBy = "The wife",
                              Country = "Italy"
                          };

        DataContext.Dinners.Add(dinner);
        DataContext.SaveChanges();

        var savedDinner = (from d in DataContext.Dinners
                           where d.DinnerId == dinner.DinnerId
                           select d).Single();

        Assert.AreEqual(dinner.Address, savedDinner.Address);
    }
}

When I run the test the Linq query that fetches the savedDinner fails with the "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection." exception. I cannot work out why.

Is what I am doing here an acceptable pattern and can anyone shed some light as to why this is not working?

Thanks.

3
  • I can see no reason why the object context is disposed. Can you debug your unit test and put a break point to savechanges method and check if datacontext is not null? then please setp to the next line and check whether datacontext is null. Commented Mar 28, 2012 at 13:24
  • Hi Daryal, the datacontext is not null in either case. The DataContext.SaveChanges(); works fine, it is the Linq query after it that fails even though the datacontext is not null. Commented Mar 29, 2012 at 4:57
  • I can foreach over the DataContext.Dinners with no problem. Note, the error I got stated that the ObjectContext has been disposed, not the DataContext. I don't know if ObjectContext is the same as the DataContext in the Linq query. Anyway, doing the following: var initDb = new SvDataContext(); initDb.Database.Initialize(true); DataContext = new SvDataContext(); in my InitTest method fixes the problem. Commented Mar 29, 2012 at 5:21

1 Answer 1

3

I ran into a similar issue this morning. The problem is caused by the where clause in the seed method. A workaround for this (for now) is rewriting this:

var dinner = context.Dinners.ToList().Where(d => d.Country == "England").Single(); 

Although not efficient (all objects are retrieved from the database and filtering will be done in memory), it did solve the ObjectDisposedException in my unit tests. In my case I only have a few objects, so I can live with it for now.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for your answer Jos. How did you isolate the problem?
It took me quite a while to figure out because I was thinking the problem was caused by IoC configuration, because of the DisposedException. I should have known better, I did not change anything there and it was working before. I had a working scenario, modified the seed code with additional models (with the where clause introduced as well), kept on commenting the newly introduced code until the problem did not occur. Uncomment the where clause code and the Exception was back. Simple but effective error tracing in case closed source frameworks let you down.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.