Тестируем EntityFramework запросы с помощью SQL Server Compact Edition

от автора

Как и все серьезные люди мы задумались о широком использвании unit тестов. В качестве платформы взяли MSpec из-за того, что некоторым членам комманды очень нравится то, что названия тестов выглядят так, словно читаешь текст, но при этом в отличии от огурца и ему подобных не приходится писать громоздкие парсеры.

Unit тестирование и моки — это безусловно хорошо и нужно, но иногда хочется и проверить, что кусок кода, работающий с базой отрабатывает корректно вцелом. Да и отчку останова в нужном месте хочется поставить и зайти туда не запуская все тяжелое приложение. В общем возникло желание тестировать базу.

Сначала решили попробовать SQLite. Маленький, теоритически много чего умеющий, в общем все с ним знакомы. Который и был запинан в качестве первого варианта, но после бодания с тем что запросы EntityFramework провайдером для SQLite строятся совсем не так как для SQL server — решено было искать ближе к корням — к Microsoft. Благо, как всегда в мире .NET, реализаций чего-либо на выбор не много, но они достаточо сурьезные. В общем решено было завести SQL Server CE.

Сразу возникает сложность. Edmx файл мы хотим под MSSQL и чтобы в нем самом никаких отсылок к SQL CE не было. Решаем этот вопрос просто и доблестно. Добавляем в проект с тестами t4 template (.tt) который производит и некоторые необходимые манипуляции с описанием схемы.

Для начала привычной рукой ставим Nuget пакеты

Install-Package SqlServerCompact Install-Package EntityFramework.SqlServerCompact 

Далее достаем из edmx SSDL и заменяем в ней Provider на SQL CE, и приводим типы из специфичных для SQL Server в SQL CE подмножество.

... <#  var di = new DirectoryInfo(Host.ResolvePath("..\\DataAccessLayer\\")).FullName; var xmlDocument = new XmlDocument(); xmlDocument.Load(Path.Combine(di,"Entities.edmx")); var xmlNamespaceManager = new XmlNamespaceManager(xmlDocument.NameTable); xmlNamespaceManager.AddNamespace("edmx", "http://schemas.microsoft.com/ado/2009/11/edmx"); xmlNamespaceManager.AddNamespace("ssdl", "http://schemas.microsoft.com/ado/2009/11/edm/ssdl");  // выкусываем SSDL из EDMX  var selectSingleNode = xmlDocument.SelectSingleNode("//ssdl:Schema[@Namespace='ТУТ_ИМЯ_НУЖНОЙ_СХЕМЫ']", xmlNamespaceManager);  // Заменяем Provider   ((XmlElement) selectSingleNode).SetAttribute("Provider", "System.Data.SqlServerCe.4.0");  // обрабатываем типы // например foreach (XmlElement node in xmlDocument.SelectNodes("//ssdl:Property[@Type='varbinary(max)']", xmlNamespaceManager)) { 	node.SetAttribute("Type","image"); }          #> 

После этого получаем специально подготовленную ssdl, которую мы хотим скормить нашему контексту.
Сперва мы делаем ее ресурсом — в свойствах объекта и на всякий случай в проекте можно прописать более вменяемое чем стандартное имя тэгом LogicalName

    <EmbeddedResource Include="SqlCompact.ssdl">       <AutoGen>True</AutoGen>       <DesignTime>True</DesignTime>       <DependentUpon>SqlCompact.tt</DependentUpon>       <LogicalName>SqlCompact.ssdl</LogicalName>     </EmbeddedResource> 

В шаблонах, создаваемых EF для контекста мы конструктор по умолчанию сделали приватным, а публичный конструктор, который добавили, всегда требует наличие параметра IConnectionString, реализации которого занимаются выдачей ConnectionString для всех желающих. В коде проекта этот интерфейс мапится на выдачу стандартной реализации. Для тестов реализация IConnectionString должна возвращать provider как System.Data.SqlServerCe.4.0 и Persist Security Info=True — иначе не взлетит. Кроме того в connectionString обязательно нужно заменить оригинальную ssdl на сгенерированую и вкомпилированую в ресурс выше.

Начинаем писать тесты, для которых базу создаем entities.Database.Create() и радумеся возможности тестировать чуть больше чем раньше.

Итого:
1) Ставим пакеты
2) Выкусываем SSDL с помощью t4 и меняем в ней типы
3) Меняем provider в SSDL и в connectionstring (если nuget глюкнул — то и в App.config)

Если же хочется все-таки SQLite — то алгритм схожий, но созданием таблиц придется заняться самостоятельно из-за корявой реализации autoincrement типа в оной и можно забыть о внешних ключах.

ссылка на оригинал статьи http://habrahabr.ru/post/202674/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *