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.

skaffman
  • 398,947
  • 96
  • 818
  • 769
Gerhard Wessels
  • 681
  • 1
  • 9
  • 18
  • 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. – daryal Mar 28 '12 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. – Gerhard Wessels Mar 29 '12 at 04: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. – Gerhard Wessels Mar 29 '12 at 05:21

1 Answers1

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.

lee-m
  • 2,269
  • 17
  • 29
  • Thank you for your answer Jos. How did you isolate the problem? – Gerhard Wessels Mar 30 '12 at 05:08
  • 1
    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. – Jos van Velzen Mar 30 '12 at 08:08