2012-04-25 5 views
12

Я использую Code First для сопоставления классов существующей базе данных. Мне нужен способ модульного тестирования этих сопоставлений, которые представляют собой смесь основанных на соглашениях, основанных на атрибутах и ​​свободно-api.Как я могу выполнить единичный тест Первых сопоставлений кода Entity Framework?

Для модульного тестирования мне нужно подтвердить, что свойства классов сопоставляются с правильными именами таблиц и столбцов в базе данных. Этот тест необходимо выполнить против контекста и сначала должен охватывать все параметры конфигурации для кода.

На очень высоком уровне, я смотрел бы утверждать что-то вроде (псевдо-код):

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

Ну мне не нравится EF, если это возможно оценить возможность использования NHibernate, с NHibernate вы можете проверить свои сопоставления очень легко – Jupaol

+0

@ Jupaol приятно знать, мы используем как EF, так и NH и имеем наши проблемы с обоими – STW

ответ

0

Единственный способ, которым я могу думать, чтобы покрыть все возможные опции будет использовать Entity Framework Power Tools, чтобы предварительно скомпилировать представления вашего DbContext и, вероятно, использовать комбинацию отражения для этого сгенерированного типа и RegEx для самого сгенерированного кода, чтобы проверить, что все отображается так, как вы хотите. Звучит довольно болезненно для меня.

Еще одна вещь, которая приходит на ум - это создать фасад вокруг DbModelBuilder, чтобы перехватить и проверить все, что проходит через него, но я не знаю, справлялось бы ли это с материалом, основанным на конвенциях. Также звучит болезненно.

Как менее полная, но гораздо более простая альтернатива, вы можете, вероятно, выбить большую часть этого, переключаясь на атрибутивное отображение, где это возможно. Это позволит вам создать базовый тестовый класс, скажем, ModelTesting <TEntity>, который включает в себя несколько методов испытаний, которые используют отражение, чтобы убедиться, что TEntity имеет:

  • Одиночная TableAttribute.
  • Каждое свойство имеет один атрибут ColumnAttribute или NotMappedAttribute.
  • По крайней мере одно свойство с KeyAttribute.
  • Каждый тип свойства сопоставляется с совместимым типом базы данных.

Вы даже можете зайти так далеко, чтобы обеспечить соблюдение соглашения об именах, основанное на именах свойств и класса (с оговоркой для типов таблицы на иерархию). Также можно было бы проверить сопоставления внешних ключей. Это базовый класс с однократной записью, который вы можете получить один раз для каждого из ваших типов моделей и поймать большинство своих ошибок (ну, во всяком случае, он улавливает мою часть).

Все, что не может быть представлено атрибутами, такими как наследование TPH и т. Д., Становится немного сложнее. Интеграционный тест, который запускает DbContext и делает FirstOrDefault для Set <. TEntity >(), вероятно, будет охватывать большинство этих баз, если ваш DbContext не создает вашу базу данных для вас.

+0

Спасибо за вход Sean! Я рассматриваю менее комплексные подходы, такие как использование одного метода конфигурации, и посмотрю на инструменты электропитания EF, я не знал о них. – STW

0

Если вы написали метод

public static string ToMappingString(this Widget obj) 

Тогда вы могли бы легко тестируем с помощью утверждения тестов (www.approvaltests.ком или NuGet)

Там есть видео здесь: http://www.youtube.com/watch?v=vKLUycNLhgc

Однако, если вы хотите, чтобы проверить «Мои объекты сохранить и retrive себя» Тогда это идеальное место «тестирования теории, основанной»

Теория на основе тестирования Большинство модульного тестирования принимают форму

Given A,B expect C 

теории на основе тестирования

Given A,B expect Theory 

Прелесть этого нет необходимости беспокоиться о том, какой именно вид А & B берут, так как вам не нужно знать C, так что любой генератор случайных чисел будет работать.

Пример 1: Тестирование складывают и вычитают методы

Обычно вы бы такие вещи, как

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

Однако если вы написали тест Theory это будет выглядеть

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

Теперь, когда вы понимать Теория, основанная на тестировании, теория, которую вы пытаетесь провести, -

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

Другая идея, которую следует рассмотреть, - использовать Linq и ToString().

Для eaxample этого:

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

будет приводить это для поставщика SQL Server:

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

Теперь мы могли бы скрыть все это в какой-то метод расширения, что и разбирает полученный SQL это будет выглядеть почти как Ваш псевдо-код:

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

Проект для расширения:

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

Similary Мы могли бы создать GetSqlTableNameFor().

UPDATE: Я решил посмотреть на некоторые Парсеры посвящает SQL, так что это решение является более общим, очевидно, есть такая вещь для .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/

 Смежные вопросы

  • Нет связанных вопросов^_^