lucamilan
5/11/2012 - 10:12 AM

Custom Scenario for better EF CodeFirst Integration Tests

Custom Scenario for better EF CodeFirst Integration Tests

using System;
using System.Configuration;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using MySolutionStudio.Infrastructure.Data;
using MySolutionStudio.Infrastructure.IntegrationTests.DataScenario;
using NUnit.Framework;
using Shouldly;

namespace MyProject.Infrastructure.IntegrationTests
{
    [TestFixture, Explicit]
    internal class SqlServerDbSchemaFixture : DbContextFixtureBase<DefaultScenario, EntityFrameworkDataContext>
    {
        protected override string ConnectionString
        {
            get
            {
                return ConfigurationManager.ConnectionStrings["DefaultDb"].ConnectionString;
            }
        }

        protected override IDbConnectionFactory DbConnectionFactory
        {
            get
            {
                return new SqlConnectionFactory();
            }
        }

        [Test]
        public void posso_creare_lo_schema()
        {
            string sql = Scenario.ToString();
            sql.Length.ShouldBeGreaterThan(0);
            Console.WriteLine(sql);
        }
    }
}
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.SqlClient;
using MySolutionStudio.Infrastructure.Data;

namespace MyProject.Infrastructure.IntegrationTests.DataScenario
{
    /// <summary>
    /// </summary>
    internal abstract class MyProjectInitializer : IDatabaseInitializer<EntityFrameworkDataContext>
    {
        /// <summary>
        /// 
        /// </summary>
        protected string Sql { get; set; }

        /// <summary>
        /// </summary>
        public bool IsSqlCe { get; private set; }

        #region IDatabaseInitializer<EntityFrameworkDataContext> Members

        /// <summary>
        /// </summary>
        /// <param name="context"> </param>
        public void InitializeDatabase(EntityFrameworkDataContext context)
        {
            IsSqlCe = context.Database.Connection.DataSource != null &&
                      context.Database.Connection.DataSource.EndsWith(".sdf", StringComparison.OrdinalIgnoreCase);

            if (context.Database.Exists())
            {
                if (!IsSqlCe)
                {
                    string database = context.Database.Connection.Database;
                    string alterCommand = string.Format("ALTER DATABASE {0} SET SINGLE_USER WITH ROLLBACK IMMEDIATE", database);
                    using (var conn = new SqlConnection(context.Database.Connection.ConnectionString))
                    {
                        var command = new SqlCommand(alterCommand, conn);
                        command.Connection.Open();
                        command.ExecuteNonQuery();
                        command.Connection.Close();
                    }
                }
                context.Database.Delete();
            }

            context.Database.Create();

            Sql = ((IObjectContextAdapter) context).ObjectContext.CreateDatabaseScript();

            if (!IsSqlCe)
            {
                var commands = new List<string>();

                foreach (string command in commands)
                {
                    Sql += command + Environment.NewLine;
                    context.Database.ExecuteSqlCommand(command);
                }
            }

            Seed(context);
        }

        #endregion

        /// <summary>
        /// </summary>
        /// <param name="context"> </param>
        protected virtual void Seed(EntityFrameworkDataContext context)
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return Sql ?? string.Empty;
        }
    }
}
using System;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Objects;
using NUnit.Framework;

namespace MyPrj.Infrastructure.IntegrationTests
{
    /// <summary>
    /// 
    /// </summary>
    public abstract class DbContextFixtureBase<TScenario, TContext>
        where TScenario : IDatabaseInitializer<TContext>, new() where TContext : DbContext
    {
        /// <summary>
        /// 
        /// </summary>
        protected TScenario Scenario { get; private set; }
        
        /// <summary>
        /// 
        /// </summary>
        protected TContext DataContext { get; private set; }

        /// <summary>
        /// 
        /// </summary>
        protected virtual IDbConnectionFactory DbConnectionFactory
        {
            get { return new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0"); }

        }

        /// <summary>
        /// 
        /// </summary>
        protected virtual string ConnectionString
        {
            get
            {
                return string.Format(@"DataSource=.\{0}.sdf", typeof (TScenario).Name.ToLowerInvariant());
            }
        }

        /// <summary>
        /// 
        /// </summary>
        protected ObjectContext ObjectContext
        {
            get { return ((IObjectContextAdapter)DataContext).ObjectContext; }
        }

        /// <summary>
        /// 
        /// </summary>
        [TestFixtureSetUp]
        public void Setup()
        {            
            DataContext = InitDataContext();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private TContext InitDataContext()
        {
            var ctor = typeof (TContext).GetConstructor(new[] {typeof (DbConnection)});

            if (ctor == null)
            {
                throw new ApplicationException(
                    "Il data context deve avere un costruttore che accetti un oggetto di tipo DbConnection");
            }

            IDbConnectionFactory defaultConnectionFactory = DbConnectionFactory;

            Database.DefaultConnectionFactory = defaultConnectionFactory;

            DbConnection dbConnection = defaultConnectionFactory.CreateConnection(ConnectionString);

            var dataContext = (TContext)ctor.Invoke(new object[] { dbConnection });

            Scenario = new TScenario();
            Scenario.InitializeDatabase(dataContext);

            return dataContext;
        }

        /// <summary>
        /// 
        /// </summary>
        [TestFixtureTearDown]
        public void ShutDown()
        {
            DataContext.Dispose();
        }
    }
}