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/
Добавить комментарий