четверг, 18 октября 2007 г.

NDbUnit и MySQL

Ситуация: для тестирования в проекте используется NUnit + NDbUnit для тестирования работы с базой. Проект работал на MS SQL Server и все было прекрасно. Потом встала задача переделать все на MySQL, что и было сделано, но возникла проблема: NDbUnit с MySQL не дружит. Тоесть NDbUnit поддеживает только SQL Server и OLE DB базы. Ну казалось бы - OLE DB поддерживает, так и используем OLE DB provider для MySQL! Но не тут то было... Сначала встала проблемма, что официального провайдера нет. Нашел тот, что нашел: [sourceforge.net]. Но и с ним не заработало (кстати, позже нашел еще один: [cherrycitysoftware.com] Его не пробовал, он 10$ стоит, хотя и бесплатно можно использовать, но с морокой). Погуглил получше и нашел решение [forums.microsoft.com], хотя и не очень красивое:
  1. Идем в "Панель Управления" - "Администрирование" - "Источники данных (ODBC)". Там нужно добавить "Системный DSN" для MySQL базы к которой мы хотим приконнектиться, при этом в качестве драйвера выбираем MySQL ODBC 3.51 (можно скачать с оффициального сайта [dev.mysql.com]). В настройках драйвера выставляем все, что положено (кстати, сюда мы еще вернемся), DataSource Name я дал такое же, как у базы.
  2. Потом при создании Connection String в Visual Studio для Datasource выбираем ".Net Framework Data Provider for OLE DB"
  3. Для OLE DB Provider используем MSDataShape
  4. Для "Server or filename" используем DataSource Name, которое дали на шаге 2.
  5. Жмем "Test Connection" и радуемся.
Но не долго. Хотя MySQL через OLE DB мы к NDbUnit'у прикрутили, он все равно работает неправильно, т.к. внутри себя геренирует неправильные CRUD (Create Read Update Delete) SQL запросы. К счастью, NDbUnit OpenSource'ный, и как мне сказали "Если очень хочется, но нельзя - все возможно". Подсоединяем к проекту исходники NDbUnit.Core, ставим точку останова на той строке, в которой возникает ошибка в тесте (берем из NUnit'а). Ctrl+Alt+P и присоединяемся к процессу NUnit'a. Запускаем тест, попадаем в Visual Studio, по F11 идем вглубь NUnit'a и находим багу - откуда-то берется еще одна колонка с пустым ( "" ) именем, которая добавляется в запрос. С какой радости, мне выяснить не удалось - ставлю заплатку (проверяем, что имя колонки не является пустой строкой - точно ничего не испортит). Ура! Почти заработало: теперь вываливается на строке запроса к полю базы с именем "Version". Ну да - зарезервированное слово в MySQL. Надо писать так: `Version`. Ну, это решается совсем просто: ставим QuotePrefix и QuoteSuffix у OleDbCommandBuilder'a равными "`" . Казалось бы все. Не совсем: у нашей базы сложные связи друг сдругом, которые надо отключить на время тестов (для MS SQL использовалась недокументированная хранимая процедура "sp_msforeachtable" чтобы пройтись по всем таблицам и выполнить "ALTER TABLE ? NOCHECK CONSTRAINT all", для MySQL этот запрос не подходит). У MySQL же есть "SET FOREIGN_KEY_CHECKS = 0" но работает это только на session. А они открываются опять же где? Внутри NDbUnit'a! И до них не добраться. НО! Помните я в пункте 1) выше говорил что мы еще вернемся к настройкам драйвера? Там есть замечательное поле, навроде "set initial sql statement" (Точного названия не помню - нет под рукой). Вот туда и пишем "SET FOREIGN_KEY_CHECKS = 0". Теперь все нормально наконец-то.
Это решение хоть и работает, но вызывает у меня не лучшие эмоции - добавление источника данных ODBC, через десятые руки работа с базой, внесение изменений в исходники NDbUnit'a... Должен быть другой способ, которого я не нашел. Если кто знает - подскажите в какую сторону смотреть.