Entity Framework Code First: Как заполнить базу данных для модульного тестирования

Мой вопрос и код основан наCode First Entity Framework Примеры тестов модулей Сообщение блога. Я использую SQL Compact 4.0, и поэтому мои модульные тесты выполняются на реальной базе данных с использованием реальных данных, аналогичных описанным в сообщении в блоге.

Я хочу заполнить свою производственную базу данных значениями по умолчанию в некоторых таблицах, но при запуске модульных тестов я хочу добавить дополнительные данные и обновить некоторые значения по умолчанию.

Я создал собственный класс Initializer, который заполняет базу данных значениями по умолчанию. Для моих модульных тестов я создал еще один пользовательский инициализатор, который наследует от первого, который выполняет тестирование заполнения и / или модификаций:

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();
    }
}

Я также использую базовый класс для своих модульных тестов, который инициализирует тестовую базу данных следующим образом:

[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);
        }
    }
}

Фактический юнит-тест выглядит так:

[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);
    }
}

Когда я запускаю тест, запрос Linq, который извлекает saveDinner, завершается с ошибкой: «Экземпляр ObjectContext был удален и больше не может использоваться для операций, требующих подключения». исключение. Я не могу понять, почему.

Является ли то, что я делаю здесь, приемлемой схемой, и может кто-нибудь пролить свет на то, почему это не работает?

Благодарю.

 daryal28 мар. 2012 г., 15:24
Я не вижу причин, по которым контекст объекта располагается. Можете ли вы отладить свой модульный тест и поставить точку останова в методе savechanges и проверить, не является ли datacontext нулевым? затем, пожалуйста, установите следующую строку и проверьте, является ли datacontext нулевым.
 Gerhard Wessels29 мар. 2012 г., 07:21
Я могу без проблем обращаться к DataContext.Dinners. Обратите внимание, я получил ошибку, указав, что ObjectContext был удален, а не DataContext. Я не знаю, совпадает ли ObjectContext с DataContext в запросе Linq. В любом случае, делаем следующее: var initDb = new SvDataContext (); initDb.Database.Initialize (истина); DataContext = new SvDataContext (); в моем методе InitTest исправляет проблему.
 Gerhard Wessels29 мар. 2012 г., 06:57
Привет, Дарьял, в обоих случаях datacontext не является нулевым. DataContext.SaveChanges (); работает нормально, это запрос Linq после него, который завершается неудачей, хотя datacontext не является нулевым.

Ответы на вопрос(1)

Решение Вопроса

ением where в методе seed. Обходной путь для этого (пока) переписывает это:

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

Хотя это и неэффективно (все объекты извлекаются из базы данных и фильтрация будет выполняться в памяти), решениеObjectDisposedException в моих модульных тестах. В моем случае у меня есть только несколько объектов, поэтому я могу жить с этим сейчас.

 Jos van Velzen30 мар. 2012 г., 10:08
Мне потребовалось много времени, чтобы понять, потому что я думал, что проблема была вызвана конфигурацией IoC, из-за DisposedException. Я должен был знать лучше, я ничего не изменил там, и это работало раньше. У меня был рабочий сценарий, я модифицировал начальный код с помощью дополнительных моделей (с введенным также предложением where) и продолжал комментировать недавно введенный код, пока проблема не возникла. Раскомментируйте код предложения where и исключение вернулось. Простое, но эффективное отслеживание ошибок в случае, если закрытые исходные фреймворки вас разочаровали.
 Gerhard Wessels30 мар. 2012 г., 07:08
Спасибо за ваш ответ Jos. Как вы изолировали проблему?

Ваш ответ на вопрос