2012-04-25 17 views
12

Używam Code First do mapowania klas do istniejącej bazy danych. Potrzebuję sposobu, aby przetestować te mapowania, które są połączeniem opartego na konwencjach, opartego na atrybutach i płynnego API.W jaki sposób mogę przetestować kodowanie jednostek Entity Framework Code First?

Aby przetestować jednostkę, muszę potwierdzić, że właściwości klas są odwzorowane na prawidłowe nazwy tabel i kolumn w bazie danych. Test ten należy wykonać w kontekście i powinien on obejmować wszystkie opcje konfiguracji dla kodu.

na bardzo wysokim poziomie, byłbym patrząc twierdzić coś podobnego (pseudo-kod):

Assert.IsTrue(context.TableFor<Widget>().IsNamed("tbl_Widget")); 
Assert.IsTrue(context.ColumnFor<Widget>(w => w.Property).IsNamed("WidgetProperty")); 
+1

Dobrze Nie lubię EF, jeśli to możliwe oceń możliwość użycia NHibernate, dzięki NHibernate możesz przetestować swoje mapowania naprawdę łatwo – Jupaol

+0

@Jupaol dobrze wiedzieć, używamy zarówno EF, jak i NH i mamy nasze problemy zarówno z – STW

Odpowiedz

0

Jedyny sposób mogę myśleć, aby pokryć każdą możliwą opcją byłoby użyć podmiotu Framework Power Tools do wstępnej kompilacji widoków twojego DbContext i prawdopodobnie użyje kombinacji refleksji na temat tego wygenerowanego typu i RegEx na wygenerowanym kodzie, aby zweryfikować, czy wszystko mapuje tak, jak chcesz. Brzmi dość bolesnie dla mnie.

Inną rzeczą, która przychodzi do głowy jest stworzenie fasady wokół DbModelBuilder, aby przechwytywać i sprawdzać wszystko, co przechodzi przez nią, ale nie wiem, czy to poradziłoby z konwencjami. Również brzmi bolesne.

Jako mniej kompletne, ale znacznie łatwiejszy alternatywa, prawdopodobnie można wybić dużą część tego, przełączając się atrybut oparte mapowanie, jeśli możliwe. Pozwoliłoby to utworzyć klasę testową bazą, powiedzmy, ModelTesting <TEntity>, który obejmuje kilka metod badawczych, które używają refleksji, aby sprawdzić, TEntity posiada:

  • Jeden TableAttribute.
  • Każda właściwość ma jedną właściwość ColumnAttribute lub NotMappedAttribute.
  • Co najmniej jedna właściwość o wartości KeyAttribute.
  • Każdy typ właściwości odwzorowuje zgodny typ bazy danych.

Można nawet posunąć się do egzekwowania konwencji nazewnictwa opartej na nazwach właściwości i klasy (z zastrzeżeniem typów tabeli na hierarchię). Możliwe byłoby również sprawdzenie odwzorowań kluczy obcych. Jest to bazowa klasa jednokrotnego zapisu, którą można uzyskać od razu dla każdego typu modelu i złapać większość swoich błędów (cóż, i tak w większości przypadków trafia ona do kopalni).

Wszystko, co nie może być reprezentowane przez atrybuty, takie jak dziedziczenie TPH itp., Staje się nieco trudniejsze. Test integracji, który uruchamia DbContext i czy FirstOrDefault na Set <TEntity>() prawdopodobnie pokryłby większość z tych baz, zakładając, że twój DbContext nie generuje twojej bazy danych.

+0

Dzięki za dane wejściowe Sean! Zastanawiam się nad mniej kompleksowymi podejściami, takimi jak zastosowanie pojedynczej metody konfiguracji i przyjrzymy się narzędziom elektromagnetycznym EF, o których nie wiedziałem. – STW

0

Jeśli napisałeś metodę

public static string ToMappingString(this Widget obj) 

Następnie można łatwo testowania to poprzez badania homologacyjne (www.approvaltests.com lub Nuget)

Istnieje wideo tutaj: http://www.youtube.com/watch?v=vKLUycNLhgc

Jednakże, jeśli szukasz, aby przetestować „Moje obiekty zapisać i sprowadzaniu siebie” to jest to idealne miejsce „teoria Based Testing”

Teoria testowania oparty Większość testów jednostkowych przybrać formę

Given A,B expect C 

Teoria testowania oparty jest

Given A,B expect Theory 

Piękno to nie ma potrzeby się martwić o których szczególną postać A & B odbioru, ponieważ nie trzeba znać C, więc każdy losowy generator zadziała.

Przykład 1: Testowanie dodawać i odejmować metody

Normalnie musiałbyś rzeczy jak

Assert.AreEqual(5, Add(2,3)); 
Assert.AreEqual(9, Add(10,-1)); 
Assert.AreEqual(10, Add(5,5)); 
Assert.AreEqual(7, Subtract(10,3)); 

Jednak jeśli napisali egzamin teoretyczny będzie wyglądać

for(int i = 1; i < 100; i++) 
{ 
    int a = random.Next(); 
    int b = random.Next(); 
    Assert.AreEqual(a, Subtract(Add(a,b),b, string.Format("Failed for [a,b] = [{0},{1}], a,b));   
} 

teraz, że Rozumiem, że testy oparte na teorii, teoria, którą próbujesz przetestować, to:

Given Model A 
When A is stored to the database, and retrieved the resulting object is equal to A 
1

Innym pomysłem do rozważenia jest użycie Linq i ToString().

Dla eaxample następująco:

context.Widget.Select(c => c.Property).ToString() 

Spowoduje to dla SQL Server Provider:

"SELECT [Var_3].[WidgetProperty] AS [WidgetProperty] FROM [dbo].[Widget]..." 

Teraz możemy ukryć to wszystko w jakiś sposób rozszerzenie, które i analizuje wynikające SQL wyglądałby prawie jak Twój pseudokod:

Assert.IsTrue(context.Widgets.GetSqlColumnNameFor(w => w.Property).IsNamed("WidgetProperty")); 

Szkic do rozszerzenia:

public string GetSqlColumnNameFor<TSource>(this DbSet<T> source, Expression<Func<TSource, TResult>> selector) 
{ 
    var sql = source.Select(selector).ToString(); 

    var columnName = sql... // TODO : Some regex parsing 

    return 
     columnName; 
} 

Na podobnej zasadzie możemy utworzyć GetSqlTableNameFor().

UPDATE: Postanowiłem poszukać pewnych parserami poświęca SQL, więc to rozwiązanie jest bardziej uniwersalne, oczywiście istnieje taka rzecz NET:

http://www.dpriver.com/blog/list-of-demos-illustrate-how-to-use-general-sql-parser/generate-internal-query-parse-tree-in-xml-for-further-processing/

Powiązane problemy