【问题标题】:Entity Framework Code First: How to seed a database for unit testing实体框架代码优先:如何为数据库播种以进行单元测试
【发布时间】:2012-04-12 01:38:43
【问题描述】:

我的问题和代码基于Code First Entity Framework Unit Test Examples 博客文章。我正在使用 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);
    }
}

当我运行测试时,获取 savedDinner 的 Linq 查询失败,并显示“ObjectContext 实例已被释放,不能再用于需要连接的操作。”例外。我不知道为什么。

我在这里所做的是否是一种可接受的模式,任何人都可以解释为什么这不起作用?

谢谢。

【问题讨论】:

  • 我看不出为什么要处理对象上下文。您可以调试您的单元测试并在 savechanges 方法中设置一个断点并检查 datacontext 是否不为空?那么请setp到下一行,检查datacontext是否为null。
  • 嗨 Daryal,无论哪种情况,datacontext 都不为空。 DataContext.SaveChanges();工作正常,即使数据上下文不为空,它之后的 Linq 查询也会失败。
  • 我可以毫无问题地遍历 DataContext.Dinners。请注意,我得到的错误表明 ObjectContext 已被处理,而不是 DataContext。我不知道 ObjectContext 是否与 Linq 查询中的 DataContext 相同。无论如何,请执行以下操作: var initDb = new SvDataContext(); initDb.Database.Initialize(true); DataContext = new SvDataContext();在我的 InitTest 方法中解决了这个问题。

标签: c# testing ef-code-first seed


【解决方案1】:

今天早上我遇到了类似的问题。问题是由种子方法中的 where 子句引起的。一个解决方法(目前)是重写这个:

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

虽然效率不高(所有对象都从数据库中检索,过滤将在内存中完成),但它确实解决了我的单元测试中的ObjectDisposedException。就我而言,我只有几个对象,所以我现在可以忍受它。

【讨论】:

  • 感谢您的回答乔斯。您是如何隔离问题的?
  • 我花了很长时间才弄清楚,因为我认为问题是由 IoC 配置引起的,因为 DisposedException。我应该更清楚,我没有改变任何东西,它以前工作过。我有一个工作场景,用其他模型修改了种子代码(也引入了 where 子句),继续评论新引入的代码,直到问题没有发生。取消注释 where 子句代码,异常又回来了。简单而有效的错误跟踪,以防闭源框架让您失望。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-04
  • 2013-07-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多