2012-03-28 20 views
5

Mi pregunta y código se basan en la publicación de blog Code First Entity Framework Unit Test Examples. Estoy usando SQL Compact 4.0 y, como tal, mis pruebas unitarias se ejecutan en la base de datos real utilizando datos reales similares a los que se describen en la publicación del blog.Código de Entity Framework Primero: Cómo inicializar una base de datos para pruebas de unidades

Quiero inicializar mi base de datos de producción con los valores predeterminados en algunas de las tablas, pero cuando ejecuto las pruebas de mi unidad deseo agregar datos adicionales y actualizar algunos de los valores predeterminados.

He creado una clase de inicializador personalizada que inicia la base de datos con los valores predeterminados. Para mis pruebas de unidad que he creado otro inicializador personalizado que hereda de la primera que hace la siembra de la prueba específica y/o modificaciones:

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

También uso una clase base para mis pruebas de unidad que inicializa la base de datos de prueba como por lo que:

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

la prueba de unidad real se parece a esto:

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

Cuando ejecuto la prueba de la consulta LINQ que obtiene el savedDinner falla con el "La instancia de ObjectContext se ha eliminado y ya no se puede usar para operaciones que requieren una conexión". excepción. No puedo entender por qué.

Es lo que estoy haciendo aquí un patrón aceptable y ¿alguien puede arrojar algo de luz sobre por qué esto no está funcionando?

Gracias.

+0

No veo ninguna razón por la que se elimine el contexto del objeto. ¿Puedes depurar tu prueba de unidad y poner un punto de ruptura para guardar el método de cambio y verificar si el contexto de datos no es nulo? luego, establezca la siguiente línea y verifique si datacontext es nulo. – daryal

+0

Hola, Daryal, el contexto de datos no es nulo en ninguno de los casos. DataContext.SaveChanges(); funciona bien, es la consulta Linq después de que falla aunque el contexto de datos no es nulo. –

+0

Puedo foreach sobre los DataContext.Dinners sin ningún problema. Tenga en cuenta que el error que he recibido indica que ObjectContext ha sido eliminado, no DataContext. No sé si ObjectContext es lo mismo que DataContext en la consulta de Linq. De todos modos, haciendo lo siguiente: var initDb = new SvDataContext(); initDb.Database.Initialize (true); DataContext = new SvDataContext(); en mi método InitTest corrige el problema. –

Respuesta

3

Me encontré con un problema similar esta mañana. El problema es causado por la cláusula where en el método de semilla. Una solución para esto (por ahora) está reescribiendo esto:

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

Aunque no es eficiente (todos los objetos se recuperan de la base de datos y el filtrado se llevará a cabo en la memoria), que resolvió el ObjectDisposedException en mis pruebas de unidad. En mi caso, solo tengo algunos objetos, así que puedo vivir con eso por el momento.

+0

Gracias por su respuesta Jos. ¿Cómo aisló el problema? –

+1

Me llevó bastante tiempo darme cuenta porque estaba pensando que el problema fue causado por la configuración de IoC, debido a la DisposedException. Debería haberlo sabido mejor, no cambié nada allí y estaba funcionando antes. Tenía un escenario de trabajo, modifiqué el código de semilla con modelos adicionales (con la cláusula where introducida también), seguí comentando el código recién introducido hasta que el problema no ocurrió. Descomente el código de cláusula where y la Excepción regresó. Rastreo de errores simple pero efectivo en caso de que los marcos de código cerrado te decepcionen. –

Cuestiones relacionadas