La mia domanda e il mio codice si basano sul post del blog Code First Entity Framework Unit Test Examples. Sto usando SQL Compact 4.0 e in quanto tale i miei test di unità sono in esecuzione contro il database reale utilizzando dati reali simili a ciò che viene descritto nel post del blog.Codice quadro entità Primo: come effettuare il seeding di un database per il test dell'unità
Desidero seminare il mio database di produzione con valori predefiniti in alcune tabelle ma durante l'esecuzione dei test di unità, desidero aggiungere ulteriori dati e aggiornare alcuni valori predefiniti.
Ho creato una classe Initializer personalizzata che semina il database con i valori predefiniti. Per i miei test di unità ho creato un altro Initializer personalizzato che eredita dal primo che fa la semina il test specifici e/o modifiche:
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();
}
}
Io uso anche una classe di base per il mio test di unità che inizializza il database di test come così:
[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);
}
}
}
il test di unità reale si presenta così:
[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);
}
}
Quando eseguo il test della query LINQ che recupera il savedDinner non riesce con il "L'istanza di ObjectContext è stata eliminata e non può più essere utilizzata per operazioni che richiedono una connessione." eccezione. Non riesco a capire perché.
È quello che sto facendo qui un modello accettabile e qualcuno può far luce sul perché questo non funziona?
Grazie.
Non riesco a vedere perché il contesto dell'oggetto sia stato eliminato. È possibile eseguire il debug del test dell'unità e impostare un punto di interruzione sul metodo di salvataggio e verificare se datacontext non è nullo? quindi impostare setp alla riga successiva e verificare se datacontext è nullo. – daryal
Ciao Daryal, il datacontext non è nullo in entrambi i casi. The DataContext.SaveChanges(); funziona bene, è la query di Linq dopo che fallisce anche se il datacontext non è nullo. –
Posso scavalcare DataContext.Dinners senza problemi. Nota, l'errore che ho dichiarato che l'ObjectContext è stato eliminato, non il DataContext. Non so se ObjectContext è lo stesso di DataContext nella query di Linq. Ad ogni modo, facendo quanto segue: var initDb = new SvDataContext(); initDb.Database.Initialize (true); DataContext = new SvDataContext(); nel mio metodo InitTest risolve il problema. –