Как и все серьезные люди мы задумались о широком использвании unit тестов. В качестве платформы взяли MSpec из-за того, что некоторым членам комманды очень нравится то, что названия тестов выглядят так, словно читаешь текст, но при этом в отличии от огурца и ему подобных не приходится писать громоздкие парсеры.
Unit тестирование и моки — это безусловно хорошо и нужно, но иногда хочется и проверить, что кусок кода, работающий с базой отрабатывает корректно вцелом. Да и отчку останова в нужном месте хочется поставить и зайти туда не запуская все тяжелое приложение. В общем возникло желание тестировать базу.
Сначала решили попробовать SQLite. Маленький, теоритически много чего умеющий, в общем все с ним знакомы. Который и был запинан в качестве первого варианта, но после бодания с тем что запросы EntityFramework провайдером для SQLite строятся совсем не так как для SQL server — решено было искать ближе к корням — к Microsoft. Благо, как всегда в мире .NET, реализаций чего-либо на выбор не много, но они достаточо сурьезные. В общем решено было завести SQL Server CE.
Сразу возникает сложность. Edmx файл мы хотим под MSSQL и чтобы в нем самом никаких отсылок к SQL CE не было. Решаем этот вопрос просто и доблестно. Добавляем в проект с тестами t4 template (.tt) который производит и некоторые необходимые манипуляции с описанием схемы.
Для начала привычной рукой ставим Nuget пакеты
Далее достаем из edmx SSDL и заменяем в ней Provider на SQL CE, и приводим типы из специфичных для SQL Server в SQL CE подмножество.
После этого получаем специально подготовленную ssdl, которую мы хотим скормить нашему контексту.
Сперва мы делаем ее ресурсом — в свойствах объекта и на всякий случай в проекте можно прописать более вменяемое чем стандартное имя тэгом LogicalName
В шаблонах, создаваемых 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 типа в оной и можно забыть о внешних ключах.
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 типа в оной и можно забыть о внешних ключах.