Тёмный

Примеры C#. DataGenerator. Dependency Injection 

Программирование - это просто
Просмотров 27 тыс.
50% 1

Создаем новые интерфейсы, разбираемся с зависимостями между классами, применяем паттерн Dependency Injection.
Тема на CyberForum www.cyberforum....
Поддержи развитие канала! money.yandex.r...
Qiwi Wallet +79534684569
Группа ВКонтакте: easycomp

Опубликовано:

 

30 сен 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 29   
@Yarkendar
@Yarkendar 8 лет назад
Спасибо, это лучший урок по внедрению зависимостей. Было бы очень удобно видеть урок в виде статьи :)
@sergepikovsky3385
@sergepikovsky3385 8 лет назад
30. Самое время подумать о классе который будет предоставлять данные. 1-ин класс - 1-а задача! ScriptGenerator - создает скрипт. Но он должен получать откуда то данные к этому скрипту. Для этого мы создали библиотеку TestDataGenerator.Data. В ней мы и разместим класс, предоставляющий данные нашему потребителю. Принято классы, которые работают с данными называть репозитариями. Но так как мы на стадии проектирования, то начинаем не с класса, а с интерфейса. Добавляем в библиотеку интерфейс IRepository.cs и делаем интерфейс открытым (public). 31. Возвращаемся к файлам, входящим в наше приложение. Они и являются опосредованным источником данных. Почему опосредованным? Из файла EnglishWord.txt мы не напрямую берем слова, а убираем номер строк, транскрипцию, толкование, а берем лишь вычлененное слово (слова). В какой то степени обработка коснется и остальных файлов. Т.е. наш класс-репозитарий длолжен обратится к этим файлам и предоставить потребителю информацию из них в удобном для потребителя формате. 32. Перечень этих данных четко виден в примере конечного скрипта. Помним, что почта = уникальный(!) логин + случайный ящик (ящик не запрашивается у файлов). Т.е. мы запрашиваем всего 4 сущности у репозитария - Имя, Отчество, Фамилию и логин. Все остальное - генерируем. Формируем методы для получения случайных данных из репозитария GetRandom...(); для всех 4-ех сущностей. Таким образом генератор скрипта будет абстрагирован от способа получения данных. 33. GetRandomUniqLogin() имеет одну тонкость: как определять границы сессии в течении которой формируются уникальные логины? Принимаем, что логины уникальны в течении генерации одного скрипта. Далее механизм учета уникальности сбрасывается и другой скрипт может однажды принять логин, который использовался, скажем, предыдущим скриптом. Для отработки этого механизма вводим метод инициализации репозитария void Init(); 34. Ну что? Пишем unit-test-ы на репозитарий? Нет!!! Unit-test покрывает не весь код. Даже вредно покрывать весь код! Юнит тестами покрывается основная часть кода - "Слой Бизнесс-Логики", т.е. библеотека .BL . Остальные слои не покрываем тестами исходя из идеологии unit-test-ирования. Unit-test-ами покрываются только независимые методы, которые ни к чему не привязаны. "Слой Призентации" привязана либо к файловой системе (наш случай), либо к UI, либо к приему пользовательских запросов, т.е. привязан к "Внешней Среде", которую мы не можем контролировать в unit-test-ах. Нижний слой - "Слой Доступа к данным" тоже зависит, но уже от "Источника[Хранилище] Данных" (папка Files). Это может быть и БД и т.д. Именно по этому интерфейс IRepository останется не покрытым unit-test-ированием. 35. Теперь подходим к реализации. Создаем открытый класс Repositary. 36. Наследоваться этот класс должен от IRepositary. Resharper на автомате реализует все поведение с реализацией throw new NotImplementedException(); Это очень хорошое исключение. Всегда стоит применять это исключение у нереализованых методов. Ни каких null - это приведет к серьезным ошибкам! Итак, все методы исполняют throw new NotImplementedException(); На данном этапе нас такая реализация устраивает. 37. Возвращаемся к интерфейсу IScriptGenerator и для него делаем все тоже самое, что и на предыдущих двух шагах для IRepositary. Т.е. создаем наследуемый от IScriptGenerator класс ScriptGenerator и просим Resharper сгенерировать все интерфейсные методы с заглушкой - throw new NotImplementedException(); 38. Псевдореализация интерфейсных методов (а других и нет) класса ScriptGenerator готова. Теперь в тестах мы можем заглушку объектов из null преобразовать в реальные объекты: public void Init() public void Init() { { _generator = null; -> _generator = new ScriptGenerator(); } } 39. Запускаем тестирование и убеждаемся в том, что все тесты упадут (что хорошо). 40. Возвращаемся в ScriptGenerator и приступаем к реализации: - public UserEntity GenerateUser() Код тривиальный, вся логика метода в этой сроке: entity.Email = string.Format("{0}@{1}", entity.Login, randomEmailDomain); 41. Пробуем запустить тесты и получаем сообщение о не реализации репозитария. Здесь есть тонкий момент, который важно понимать: - мы тестируем не класс репозитария, - мы тестируем ScriptGenerator, т.е. логику. - нам совершенно не важно как себя ведет класс репозитария. Но как мы можем абстрогироваться от класса репозитария если мы в нашем методе постоянно к нему обращаемся??? В 99% случаев методы одного класса будут зависеть от методов другого класса, но идеология unit-tseting заключается в том, что тестируется только код одного метода. Без зависимости от другого (третьего) метода. В этом случае разработчики прибегают к приему, которая называемся иньекция зависимости (Dependency Injection). В чем он заключается (практически)? Возвращаемся в метод GenerateUser(), конкретно его первую строку: IRepository repository = new Repositary(); - это очень "нехорошая" строка кода, т.к. она гвоздями прибивает наш метод к классу репозитария, в частности к его реализации {new Repository}. Если мы захотим заменить, то мы будем должны найти в классе ScriptGenerator все методы, в которых используется репозитарий и там его заменить на какую-то другую переменную. Это очень не удобно! 42. В таких то случаях и делают инъекцию зависимостей, которая к тому же явно показывает от каких именно классов зависит наш класс. Инъекция может быть проброшена в класс многими способами, но мы рассмотрим самый очевидный - Инъекцию Через Конструктор: a) Создаем закрытое поле для чтения типа IRepositary - private readonly IRepository _repository; б) Создаем конструктор нашего класса в котором инициируем созданое поле передаваемым в конструктор параметром. в) Заменяем все ссылки на репозитарий на ссылку на вновь созданное поле. г) Коментируем (убираем) строку создания старого экземпляра репозитария. 43. Что мы получили? Наш класс полностью избавился от зависимости от репозитария. Он по прежнему обращается к объекту репозитария, но теперь зависимость от объекта репозитария поступает от конструктора класса. Т.е управление этими зависимостями возлагается на иной класс. А именно на управляющий класс по отношению к ScriptGenerator (инстанцирующий ScriptGenerator). Для изменения зависимости ему хватит поменять параметр в конструкторе. А поскольку в качестве типа параметра мы указываем не конкретный класс, а интерфейс, то мы можем сюда подставить любой класс который реализует интерфейс параметра конструктора. А таких классов может быть уже достаточно много. Теперь можно переходить к тестовому классу!
@NatuNuarat
@NatuNuarat 8 лет назад
Сегодня на работе искала информацию по dependency injection и случайно набрела на Вашу статью на хабре. Узнала автора по аватарке XD Это было так приятно, как будто встретила старого знакомого! Спасибо за Ваши уроки! Они помогли мне освоить азы чтобы стать сейчас стажером-программистом =)
@СаняСанин-ш6у
@СаняСанин-ш6у 2 года назад
Спасибо, лучшее объяснение!
@NikitaReznikow
@NikitaReznikow 8 лет назад
Спасибо за уроки, давно хотел учить тесты, сильно помогли! Такой ворос: у меня Password_Required проходит, я так понимаю что это связано с тем что, проверяет на Empty а не на Null, ибо когда меняю проверку на null тест не проходит, хотя полностью повторил ваш код?
@WorldCount
@WorldCount 8 лет назад
Вот и я это заметил. Причем если в Mock изменить возвращаемое значение для имени на null, то начинает проходить тест и для имени. Походу везде надо проверять именно на null.
@WorldCount
@WorldCount 8 лет назад
Вообще не пойму, в коде у автора везде на Empty проверка и у него не проходит.
@jestemzbiaorusi8379
@jestemzbiaorusi8379 4 года назад
Мне кажется до меня дошло... :)
@sergepikovsky3385
@sergepikovsky3385 8 лет назад
Прошу прощения если сделал не правильно, просто конспект всегда пишу, чтобы помнил не только мозг, но и 10 пальцев, да и вспоминать легче... может пригодиться кому.
@dimabogdan1380
@dimabogdan1380 8 лет назад
+Serge Pikovsky так же делаю, отлично помогает, только конспектировать правильно нужно)
@sergepikovsky3385
@sergepikovsky3385 8 лет назад
+Dima Bogdan Интересно, что по вашему правильно? У меня особых правил нет. Ну, не совсем как акын, конечно, пишу, что слышу... стараюсь придать какую то структуру записям и если решил писать не выборочно, то стараюсь не пропускать смысловых блоков лекции/урока. Есть правила Димы Богдана? :-)
@sergepikovsky3385
@sergepikovsky3385 8 лет назад
+Dima Bogdan А, еще... когда я здесь написал "правильно", я имел ввиду без разрешения читающего лекцию.
@ТуралИскендерли
@ТуралИскендерли 2 года назад
Очень хороший урок👍 Сегодня провалился на Внедрении зависимостей на собеседовании. А теперь смотрю оказывается я им пользовался довольно таки часто не зная ему названия😄. Только опять таки что то не оговаривается. Или я не понимаю. Зачем нам поменять класс Repository если другой класс тоже все равно обязан реализовать тот же интерфейс и те же методы? И следовательно зачем депенденси инжекшн в таком случае?
@sanyasa2092
@sanyasa2092 8 лет назад
Неплохо бы уроки для Windows (UWP) . Мне например уже заказывают для девайсов на разбери.
@Milording
@Milording 8 лет назад
+sanya sa я попробую сделать уроки, Игорь посмотрит. Если подойдут, то ожидайте! :)
@arturbo3134
@arturbo3134 Год назад
репазитАрии :D
@_kul879
@_kul879 2 года назад
Ве-ли-ко-ле-п-но! Хочу также про интеграционны тесты!
@AlexS-gn9tq
@AlexS-gn9tq 6 лет назад
ВАУ!!!Спасибо огромное. Это настолько простое и наглядное объяснение! Я перечитал кучу разных статей но никак не мог въехать что это такое и зачем надо, а здесь всё так просто! Супер! Спасибо!
@vitalygaponenko4184
@vitalygaponenko4184 6 лет назад
Самое лучшее объяснение из тех, что мне удалось посмотреть. Все понятно. Спасибо! Все отлично.
@Milording
@Milording 8 лет назад
Очень круто. Жду продолжения и надеюсь, будут темы с IoC и IoC-контейнерами, а то пока это все в голове слабо связывается с DI
@BoxaShu
@BoxaShu 8 лет назад
Спасибо. жду продолжения.
@svLimones
@svLimones 8 лет назад
А будет ли показаны другие типы тестов? Авто-тесты, функциональные тесты?
@Defazze
@Defazze 8 лет назад
+Arthur “svLimones” Ishmatov В рамках этого курса - скорее всего нет
@anatoliymedinets241
@anatoliymedinets241 6 лет назад
Однозначно лайк!
@denyszorin8675
@denyszorin8675 8 лет назад
Здравствуйте, у меня есть вопрос Как правильно нужно приплюсовывать стринги ?? на собеседовании мне сказали что вот так делать нежелательно - "some string" + " new string"
@Defazze
@Defazze 8 лет назад
+Денис Зорин через string.format или (в C# 6) через интерполяцию строк
@denyszorin8675
@denyszorin8675 8 лет назад
+Программирование - это просто , нашел ответ на свой вопрос в вашем следующем уроке. Как вариант еще это при помощи стринг билдера ) спасибо за ответ )
@qwertyq2570
@qwertyq2570 8 лет назад
+Денис Зорин Странно, что в этом такого ? Надо им Рихтера дать почитать. ) "Чтобы объединить несколько строк в одну строку, используйте оператор + языка C#: String s = "Hi" + " " + "there."; // Конкатенация трех литеральных строк образует одну литеральную строку Поскольку все строки в этом коде литеральные, компилятор выполняет их конкатенацию на этапе компиляции, в результате в метаданных модуля оказывается лишь строка "Hi there.". Конкатенация нелитеральных строк с помощью оператора + происходит на этапе выполнения. Для конкатенации нескольких строк на этапе выполнения оператор + применять нежелательно, так как он создает в куче несколько строковых объектов. Вместо него рекомендуется использовать тип System.Text.StringBuilder"
Далее
Dependency Injection простыми словами
18:17
Вопрос Ребром - Серго
43:16
Просмотров 342 тыс.
КОТЯТА В ОПАСНОСТИ?#cat
00:36
Просмотров 1,8 млн
Интерфейсы на практике
7:34
Просмотров 180 тыс.
Уроки WPF. Таблицы и списки
15:45
Просмотров 50 тыс.
Уроки WPF. Основы разметки
21:00
Просмотров 101 тыс.