Database initialization Starting too late

EDITED

I am running a unit test (using nunit) for the databsae init method. I installed the test and started the database with a test case using this:

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

      

Then I run the test method:

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

      

To test my custom initializer, I created a class that inherits from it, I could use the Seed () method to do some data that I could check. This is the class:

    //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."
                    );
        }
    }

      

And the class it was derived from:

//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) { }
}

      

The problem I seem to be running into is that initialization doesn't take place until it is asserted. I checked the metadata values ​​and the values ​​are the values ​​of the SetUp () method. I have also verified that the object is marked as modified before SaveChanges () is called in the method I am testing. However, the method certainly works because the database reflects the values ​​from the method.

The original problem I was thinking was that the IsInitialized property was returning as an invalid value since it was 1 in the database, but I got false in the code.

+3


source to share


2 answers


Change Assert.AreEqual(true,

to Assert.IsTrue(

because it true

can have different shapes between types. As you noticed, it was encoded 1

in the database, which may not match exactly.



You can check if the context updates correctly before the assertion SaveChanges()

: do the assertion " TimeEdited

" first. (Replace DateTime.Now with some constant value that is easier to compare first).

+1


source


At the top of my test class, I:

[TestFixture]
public class CustomDropCreateDatabaseIfModelChangesTest
{
    protected const string connectionString = 
        "Data Source=SABERTOOTH\\POS;Initial Catalog=POS;Integrated Security=true;Pooling=false";
    protected POSDatabaseContext database;

....

}

      

I modified the test to use the new DbContext like so:



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

        POSDatabaseContext newContext = new POSDatabaseContext(connectionString);

        //use the metata table to check if it was run correctly
        //if metadata exist, which it should
        if(newContext.Metadata.Any(s => s.ID == "META"))
        {
            Metadata actual = newContext.Metadata.Single(s => s.ID == "META");

            Assert.IsTrue(actual.IsInitialized);
        }
        else
            throw new Exception("The Database was not seeded correctly");         
    }

      

So it turns out that Pieter21 was right, the context was not updated for some reason and a new context needed to be created. However, I don't know why.

0


source







All Articles