Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Public class FileListRestore
{ public string LogicalName { get; set; } public string Type { get; set; } }
protected static string NameDb = " LessonProject";
protected static string TestDbName;
private void CopyDb(StandardKernel kernel, out FileInfo sandboxFile, out string connectionString) { var config = kernel.Get< IConfig> (); var db = new DataContext(config.ConnectionStrings(" ConnectionString"));
TestDbName = string.Format(" {0}_{1}", NameDb, DateTime.Now.ToString(" yyyyMMdd_HHmmss"));
Console.WriteLine(" Create DB = " + TestDbName); sandboxFile = new FileInfo(string.Format(" {0}\\{1}.bak", Sandbox, TestDbName)); var sandboxDir = new DirectoryInfo(Sandbox);
//backupFile var textBackUp = string.Format(@" -- Backup the database BACKUP DATABASE [{0}] TO DISK = '{1}' WITH COPY_ONLY", NameDb, sandboxFile.FullName); db.ExecuteCommand(textBackUp);
var restoreFileList = string.Format(" RESTORE FILELISTONLY FROM DISK = '{0}'", sandboxFile.FullName); var fileListRestores = db.ExecuteQuery< FileListRestore> (restoreFileList).ToList(); var logicalDbName = fileListRestores.FirstOrDefault(p => p.Type == " D"); var logicalLogDbName = fileListRestores.FirstOrDefault(p => p.Type == " L");
var restoreDb = string.Format(" RESTORE DATABASE [{0}] FROM DISK = '{1}' WITH FILE = 1, MOVE N'{2}' TO N'{4}\\{0}.mdf', MOVE N'{3}' TO N'{4}\\{0}.ldf', NOUNLOAD, STATS = 10", TestDbName, sandboxFile.FullName, logicalDbName.LogicalName, logicalLogDbName.LogicalName, sandboxDir.FullName); db.ExecuteCommand(restoreDb);
connectionString = config.ConnectionStrings(" ConnectionString").Replace(NameDb, TestDbName); }
} По порядку: В строках var config = kernel.Get< IConfig> (); var db = new DataContext(config.ConnectionStrings(" ConnectionString"));
- получаем подключение к БД. TestDbName = string.Format(" {0}_{1}", NameDb, DateTime.Now.ToString(" yyyyMMdd_HHmmss")); Создаем наименование тестовой БД. //backupFile var textBackUp = string.Format(@" -- Backup the database BACKUP DATABASE [{0}] TO DISK = '{1}' WITH COPY_ONLY", NameDb, sandboxFile.FullName); db.ExecuteCommand(textBackUp); - выполняем бекап БД в папку Sandbox. var restoreFileList = string.Format(" RESTORE FILELISTONLY FROM DISK = '{0}'", sandboxFile.FullName); var fileListRestores = db.ExecuteQuery< FileListRestore> (restoreFileList).ToList(); var logicalDbName = fileListRestores.FirstOrDefault(p => p.Type == " D"); var logicalLogDbName = fileListRestores.FirstOrDefault(p => p.Type == " L"); - получаем логическое имя БД и файла логов, используя приведение к классу FIleListRestore. var restoreDb = string.Format(" RESTORE DATABASE [{0}] FROM DISK = '{1}' WITH FILE = 1, MOVE N'{2}' TO N'{4}\\{0}.mdf', MOVE N'{3}' TO N'{4}\\{0}.ldf', NOUNLOAD, STATS = 10", TestDbName, sandboxFile.FullName, logicalDbName.LogicalName, logicalLogDbName.LogicalName, sandboxDir.FullName); db.ExecuteCommand(restoreDb);
- восстанавливаем БД под другим именем (TestDbName) connectionString = config.ConnectionStrings(" ConnectionString").Replace(NameDb, TestDbName); - меняем connectionString. И теперь можем спокойно проинициализировать IRepository к SqlRepository: protected override void InitRepository(StandardKernel kernel) { FileInfo sandboxFile; string connectionString; CopyDb(kernel, out sandboxFile, out connectionString); kernel.Bind< webTemplateDbDataContext> ().ToMethod(c => new webTemplateDbDataContext(connectionString)); kernel.Bind< IRepository> ().To< SqlRepository> ().InTransientScope(); sandboxFile.Delete(); } Итак, у нас есть sandboxFile – это файл бекапа, и connectionString – это новая строка подключения (к дубликату БД). Мы копируем БД, связываем именно с SqlRepository, но базу подсовываем не основную. И с ней можно делать всё что угодно. Файл бекапа базы в конце удаляем. И дописываем уже удаление тестовой БД, после прогона всех тестов: private void RemoveDb() { var config = DependencyResolver.Current.GetService< IConfig> ();
var db = new DataContext(config.ConnectionStrings(" ConnectionString"));
var textCloseConnectionTestDb = string.Format(@" ALTER DATABASE [{0}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE", TestDbName); db.ExecuteCommand(textCloseConnectionTestDb);
var textDropTestDb = string.Format(@" DROP DATABASE [{0}]", TestDbName); db.ExecuteCommand(textDropTestDb); } Используя TestDbName, закрываем подключение (а то оно активное), и удаляем базу данных. Не забываем сделать копию Web.config: xcopy $(SolutionDir)LessonProject\Web.config $(ProjectDir)Sandbox\ /y Но кстати, иногда БД нет необходимости удалять. Например, мы хотим заполнить базу кучей данных автоматически, чтобы проверить поиск или пейджинг. Это мы рассмотрим ниже. А сейчас тест – реальное создание в БД записи: [TestFixture] public class DefaultUserControllerTest { [Test] public void CreateUser_CreateNormalUser_CountPlusOne() { var repository = DependencyResolver.Current.GetService< IRepository> ();
var controller = DependencyResolver.Current.GetService< LessonProject.Areas.Default.Controllers.UserController> ();
var countBefore = repository.Users.Count(); var httpContext = new MockHttpContext().Object;
var route = new RouteData();
route.Values.Add(" controller", " User"); route.Values.Add(" action", " Register"); route.Values.Add(" area", " Default");
ControllerContext context = new ControllerContext(new RequestContext(httpContext, route), controller); controller.ControllerContext = context;
controller.Session.Add(CaptchaImage.CaptchaValueKey, " 1111");
var registerUserView = new UserView() { ID = 0, Email = " rollinx@gmail.com", Password = " 123456", ConfirmPassword = " 123456", Captcha = " 1111", BirthdateDay = 13, BirthdateMonth = 9, BirthdateYear = 1970 };
Validator.ValidateObject< UserView> (registerUserView); controller.Register(registerUserView);
var countAfter = repository.Users.Count(); Assert.AreEqual(countBefore + 1, countAfter); } } Проверьте, что нет в БД пользователя с таким email. Запускаем, проверяем. Работает. Кайф! Тут понятно, какие мощности открываются. И если юнит-тестирование – это как обработка минимальных кусочков кода, а тут – это целый сценарий. Но, кстати, замечу, что MailNotify всё же высылает письма на почту. Так что перепишем его как сервис: /LessonProject/Tools/Mail/IMailSender.cs: public interface IMailSender { void SendMail(string email, string subject, string body, MailAddress mailAddress = null); } /LessonProject/Tools/Mail/MailSender.cs: public class MailSender: IMailSender { [Inject] public IConfig Config { get; set; }
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
public void SendMail(string email, string subject, string body, MailAddress mailAddress = null) { try { if (Config.EnableMail) { if (mailAddress == null) { mailAddress = new MailAddress(Config.MailSetting.SmtpReply, Config.MailSetting.SmtpUser); } MailMessage message = new MailMessage( mailAddress, new MailAddress(email)) { Subject = subject, BodyEncoding = Encoding.UTF8, Body = body, IsBodyHtml = true, SubjectEncoding = Encoding.UTF8 }; SmtpClient client = new SmtpClient { Host = Config.MailSetting.SmtpServer, Port = Config.MailSetting.SmtpPort, UseDefaultCredentials = false, EnableSsl = Config.MailSetting.EnableSsl, Credentials = new NetworkCredential(Config.MailSetting.SmtpUserName, Config.MailSetting.SmtpPassword), DeliveryMethod = SmtpDeliveryMethod.Network }; client.Send(message); } else { logger.Debug(" Email: {0} {1} \t Subject: {2} {3} Body: {4}", email, Environment.NewLine, subject, Environment.NewLine, body); } } catch (Exception ex) { logger.Error(" Mail send exception", ex.Message); } } }
/LessonProject/Tools/Mail/NotifyMail.cs: public static class NotifyMail { private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private static IConfig _config;
public static IConfig Config { get { if (_config == null) { _config = (DependencyResolver.Current).GetService< IConfig> ();
} return _config; } }
private static IMailSender _mailSender;
public static IMailSender MailSender { get { if (_mailSender == null) { _mailSender = (DependencyResolver.Current).GetService< IMailSender> ();
} return _mailSender; } }
public static void SendNotify(string templateName, string email, Func< string, string> subject, Func< string, string> body) { var template = Config.MailTemplates.FirstOrDefault(p => string.Compare(p.Name, templateName, true) == 0); if (template == null) { logger.Error(" Can't find template (" + templateName + ")"); } else { MailSender.SendMail(email, subject.Invoke(template.Subject), body.Invoke(template.Template)); } } } /LessonProject/App_Start/NinjectWebCommon.cs: private static void RegisterServices(IKernel kernel) {… kernel.Bind< IMailSender> ().To< MailSender> (); }
Ну и в LessonProject.UnitTest добавим MockMailSender (/Mock/Mail/MockMailSender.cs): public class MockMailSender: Mock< IMailSender> { public MockMailSender(MockBehavior mockBehavior = MockBehavior.Strict) : base(mockBehavior) { this.Setup(p => p.SendMail(It.IsAny< string> (), It.IsAny< string> (), It.IsAny< string> (), It.IsAny< MailAddress> ())) .Callback((string email, string subject, string body, MailAddress address) => Console.WriteLine(String.Format(" Send mock email to: {0}, subject {1}", email, subject))); } } В UnitTestSetupFixture.cs (/LessonProject.UnitTest/Setup/UnitTestSetupFixture.cs): protected virtual IKernel InitKernel() { … kernel.Bind< MockMailSender> ().To< MockMailSender> (); kernel.Bind< IMailSender> ().ToMethod(p => kernel.Get< MockMailSender> ().Object); return kernel; } Запускаем, тесты пройдены, но на почту уже ничего не отправляется. =============== =====START===== =============== Create DB = LessonProject_20130314_104218 Send mock email to: chernikov@googlemail.com, subject Регистрация на
=============== =====BYE! ====== ===============
|