c# - 数据库初始化运行太晚

标签 c# linq entity-framework unit-testing ef-code-first

已编辑

我正在为数据库初始化方法运行单元测试(使用 nunit)。我设置了测试并使用以下测试示例为数据库播种:

    [TestFixtureSetUp]
    public void SetUp()
    {
        //select database
        Database.DefaultConnectionFactory = new SqlConnectionFactory(connectionString);
        database = new POSDatabaseContext(connectionString);

        //drop database and recreate
        string query = "ALTER DATABASE [POS] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;";
        database.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, query);
        database.Database.Delete();
        database.Database.Create();

        //add seed value to test against
        database.Metadata.Add(new Metadata {
            ID = "META",
            IsInitialized = false,
            testBool = true,
            TimeCreated = DateTime.Now,
            TimeEdited = DateTime.Now
        });
        database.SaveChanges();
    }

然后我运行这个测试方法:

    [Test]
    public void InitializeDatabaseTestWithMatchingModel()
    {
        //set initializer for data context to test it, and run it
        Database.SetInitializer<POSDatabaseContext>(new
            CustomDropCreateDatabaseWithMatchingModelTest());
        database.Database.Initialize(true);

        //use the metadata table to check if it was run correctly
        //if metadata exist, which it should
        if(database.Metadata.Any(s => s.ID == "META"))
        {
            Metadata actual = database.Metadata.Single(s => s.ID == "META");
            Assert.IsTrue(actual.IsInitialized);
        }
        else
            throw new Exception("The Database was not seeded correctly for the test");
    }

为了测试我的自定义 Initializer,我创建了一个继承自它的类,我可以使用 Seed() 方法生成一些我可以测试的数据。这是类:

    //class is derived from class that needs to be tested so can still be used for testing
    //this class adds seed data to check the database with
    public class CustomDropCreateDatabaseWithMatchingModelTest 
        : CustomDropCreateDatabaseIfModelChanges<POSDatabaseContext>
    {
        protected override void Seed(POSDatabaseContext context)
        {
            //if metadata exist (Which it should since the database
            //shouldn't be dropped because the model is the same)
            if(context.Metadata.Any(s => s.ID == "META"))
            {
                Metadata meta = context.Metadata.Single(s => s.ID == "META");
                if(meta.IsInitialized == true)
                    throw new Exception("The database has not been dropped"+
                        " and recreated correctly during the unit test setup."
                    );
                else
                {
                    meta.IsInitialized = true;
                    meta.TimeEdited = DateTime.Now;
                    context.SaveChanges();
                }
            }
            else
                throw new Exception("Metadata not found. The database was"+
                    " either dropped because it was falsely accused of not"+
                    " having a matching model, OR the database was not seeded"+
                    " properly during unit test setup."
                    );
        }
    }

它派生的类:

//This file contains custom versions of the built in
//database intializer classes in which an SQL Statement
//is run to stop all connections to the database so that
//when the database is dropped, a database in use
//exception is not thrown.
public class CustomDropCreateDatabaseIfModelChanges<Context> 
    : IDatabaseInitializer<Context> where Context : DbContext
{
    public void InitializeDatabase(Context context)
    {
        if (context.Database.Exists())
        {
            if (!context.Database.CompatibleWithModel(true))
            {
                string query = "ALTER DATABASE [POS] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;";
                context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, query);
                context.Database.Delete();
                context.Database.Create();
            }
            //else do nothing and continue
        }
        else context.Database.Create();

        //run seed method
        Seed(context);
    }

    //OVERIDE ME
    //this method seeds the database with data
    protected virtual void Seed(Context context) { }
}

我似乎遇到的问题是初始化直到断言之后才运行。我已经检查了 Metadata actual 的值,这些值是来自 SetUp() 方法的值。我还检查了在我正在测试的方法中调用 SaveChanges() 之前对象是否被标记为已修改。但是,该方法肯定正在运行,因为数据库反射(reflect)了该方法的值。

我认为我遇到的最初问题是 IsInitialized 属性作为错误值返回,因为它在数据库中为 1,但我在代码中得到了 false。

最佳答案

Assert.AreEqual(true, 更改为 Assert.IsTrue(,因为 true 可以在类型之间有不同的形式。如您所见,它在数据库中编码为 1,可能不完全匹配。

您可以检查 SaveChanges() 是否正确更新断言之前的上下文:首先对 TimeEdited 执行断言。 (首先将 DateTime.Now 替换为一些更容易比较的常量值)。

关于c# - 数据库初始化运行太晚,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25935967/

相关文章:

entity-framework - 计数 + 分组依据 + 哪里

c# - 在 C# 中列出 GetRange

.net - 在 foreach 循环声明中使用 LINQ

c# - GroupBy 项目和项目的总数量

c# - 使用反射将 lambda 表达式作为参数传递

c# - 解决方案中的多个项目 - Entity Framework 和 ASP.Net MVC 4

c# - Memcached .Net 客户端 BufferedStream 错误

c# - 对具有动态操作数的空合并运算符进行类型检查

c# - 如何将日期时间字段转换为 2011 年 2 月 1 日之类的字符串?

c# - EF4.0 中的延迟加载正在卡住 UI