Moje pytanie i kod jest oparty na poście na blogu Code First Entity Framework Unit Test Examples. Używam SQL Compact 4.0 i jako takie moje testy jednostkowe działają w oparciu o rzeczywistą bazę danych przy użyciu rzeczywistych danych podobnych do tego, co jest opisane w poście na blogu.Kod struktury jednostki Najpierw: Jak zasiać bazę danych do testowania jednostkowego
Chcę zasiać moją produkcyjną bazę danych wartościami domyślnymi w niektórych tabelach, ale podczas uruchamiania testów jednostkowych chcę dodać dodatkowe dane i zaktualizować niektóre z domyślnych wartości.
Utworzono niestandardową klasę inicjalizatora, która zasiewa bazę danych z wartościami domyślnymi. Dla moich testów jednostkowych Stworzyłem kolejny niestandardowy inicjująca, która dziedziczy z pierwszego, dokłada test specyficzny siewu i/lub modyfikacje:
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();
}
}
Używam również klasę bazową dla moich testów jednostkowych, które inicjuje testowej bazy danych jak tak:
[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);
}
}
}
rzeczywiste testy jednostkowe wygląda następująco:
[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);
}
}
Kiedy uruchomić test kwerendy Linq, który pobiera savedDinner nie z "Instancja ObjectContext została usunięta i nie można jej już używać do operacji wymagających połączenia." wyjątek. Nie mogę zrozumieć dlaczego.
Czy to, co tutaj robię, jest akceptowalnym wzorcem i czy ktoś może rzucić nieco światła na to, dlaczego to nie działa?
Dzięki.
Nie widzę powodu, dla którego kontekst obiektu został usunięty. Czy możesz debugować swój test jednostki i umieścić punkt przerwania w metodzie savechanges i sprawdzić czy format danych nie jest pusty? następnie przejdź do następnej linii i sprawdź, czy datacontext jest pusty. – daryal
Witaj Daryal, datakontekst nie jest pusty w obu przypadkach. DataContext.SaveChanges(); działa dobrze, jest to zapytanie Linq po nim, które nie działa, nawet jeśli datacontext nie jest pusty. –
Mogę foreach nad DataContext.Dinners bez problemu. Uwaga: błąd, który otrzymałem stwierdził, że ObjectContext został usunięty, a nie DataContext. Nie wiem, czy ObjectContext jest taki sam jak DataContext w zapytaniu Linq. W każdym razie, wykonując następujące czynności: var initDb = new SvDataContext(); initDb.Database.Initialize (true); DataContext = new SvDataContext(); w mojej metody InitTest rozwiązuje problem. –