После того, как на меня оказали давление многочисленные фанатики программирования, я решил попробовать вести какой-нибудь технический блог. Учитывая размер сообщества и низкую полосу входа, на мой взгляд, очевидным выбором является Medium. (Это и я не знаю, как настроить свою веб-страницу в блоге.)

Работа в яркой обстановке иногда оставляет ограниченное творческое пространство для изучения некоторых тем. Обычно вы не должны быть тем парнем, который в конечном итоге пишет компилятор вместо того, чтобы выполнять порученную вам задачу по удалению тени от кнопки оформления заказа, однако это не следует интерпретировать как «пребывание в своей зоне комфорта». Разобравшись с этим, я хотел бы позволить себе лучше изучать темы, на которые я натыкаюсь, работая на дневной работе. (По ночам я одеваюсь в костюм из спандекса и несу правосудие над людьми, которые тестируют в производственной среде.) Моя цель - создать серию постов, посвященных тому, что я считаю интересным в мире разработки программного обеспечения или чему-то, что я хотел бы изучить но никогда не находил на это времени. Это будет скорее стиль письма «учись на ходу», а не типичный для Джона Скита стиль исчерпывающих и окончательных ответов на все ваши проблемы.

Я надеюсь, что мой каламбур в названии будет извинен.

Модульное тестирование - это основа нашего дела, и многие люди игнорируют его, чтобы реализовать еще одну или две функции. Я не буду вдаваться в подробности, почему вы должны это делать, хотя рекомендую всем включить Искусство модульного тестирования Роя Ошерова в свой список для чтения.

Работа над долгосрочными проектами с гигантскими масштабами требует настройки инфраструктуры для тестирования, и после завершения правильная работа значительно снизит вашу рабочую нагрузку. К счастью, люди умнее нас, смертных инженеров, уже сделали тяжелую работу, и мы здесь только для того, чтобы пожинать плоды их труда.
Одним из таких инструментов является генератор тестовых объектов, такой как NBuilder, используемый для генерации тестовых объектов в .NET, но эта концепция не привязана к выбранному вами языку. Fluent API упрощает создание объектов, а добавленные параметры конфигурации удобны в использовании.

Вот базовый пример с соответствующим выводом:

У первого автомобиля нет названия, и он был впервые зарегистрирован около двух тысяч лет назад, что, как я могу представить, сделает его успех на рынке подержанных автомобилей немного хлопотным. Вторая машина, с другой стороны, совершенно новая, и ее отличительное название и модель наверняка сделают ее хитом, когда она поступит в автосалоны, однако у нее нет двигателя, черт возьми.

Конструктор можно настроить для заполнения объекта через ранее упомянутый свободный API. Вы можете поставить ему новый двигатель и, возможно, даже проехать несколько дополнительных миль, пока вы уже там. Масштабирование этого подхода до более коротких POCO - это дополнительная работа, которая является инициализаторами пограничных объектов, которые существуют с C # 3.0. Чаще всего именно эта инициализация - это то, что вам нужно, и добавленная конфигурация хорошо помогает, когда необходимо проектировать объекты для конкретных тестовых случаев.

Иногда вас не интересуют сами данные, а их наличие - это то, что вы проверяете. Если бы тестовый пример заключался в проверке возможности залить дизельное топливо в ваш электромобиль, вы бы наткнулись на легкое раздражение и на моего старого друга: NullReferenceException. Несмотря на распространенное мнение, что деньги заставляют мир вращаться, это действительно легкое раздражение и легкий дискомфорт.

Мне это показалось хорошей возможностью потратить один день, чтобы сэкономить секунды на этапе настройки тестирования. Войдите в стандартный конструктор рекурсивных объектов , поддерживаемый NBuilder. Название звучит так, будто я только что нашел решение проблемы NP (степень CS отлично подходит для гибкости, как вы можете видеть на основе моей предыдущей выбранной метафоры).

Покажи мне код:

Основная идея состоит в том, чтобы взять любой класс и построить график с желаемой глубиной, используя NBuilder в качестве основы, потому что он уже выполняет такую ​​хорошую работу. Если в будущем NBuilder начнет поддерживать это поведение из коробки, этот фрагмент будет устаревшим, потому что невозможно, чтобы что-то, написанное за два часа, могло быть таким же мощным, как что-то, разработанное для производственного использования. Тем не менее, это прекрасная возможность получить представление о том, как это можно сделать, и немного глубже изучить отражение, обобщения, рекурсию и динамические объекты.

Основная проблема, которую необходимо было решить, заключалась в обеспечении универсального поведения во время выполнения, именно здесь в игру вступает отражение. Это может быть рискованным делом, поэтому инкапсуляция такого поведения - неплохая идея, однако вы должны знать, какое влияние на производительность оказывает отражение в вашей программе.

Builder выполняет итерацию по свойствам и на основе типа и текущей глубины создает сложный тип и присваивает его свойству. Причина, по которой я отслеживал глубину, заключается в круговых ссылках, которые могут вызвать переполнение стека из-за рекурсивных вызовов построителя. Когда желаемая глубина достигнута или на текущем этапе построения для данного типа нет сложных типов, может иметь место фактическая фаза построения.

Динамические объекты не являются чем-то, что следует практиковать в мире ООП, и действительно, вы не будете часто их использовать, когда примете парадигму ООП. У меня была возможность использовать в этом примере динамический объект, и хотя этого можно было избежать, я думаю, что это дает элегантное решение. Проблема в том, что и построитель списков, и построитель отдельных объектов имеют метод Build, открытый в их интерфейсе, но это два разных интерфейса. Вы можете возразить, что это нарушает принцип разделения интерфейсов и что оба интерфейса должны наследовать от интерфейса Buildable, который будет обеспечивать только функциональность сборки для клиентского кода. Динамические объекты позволяют вам использовать знания, которые у вас превосходят компилятор, и позволяют этим самородкам сделать ваш код более читабельным и / или хрупким.

Динамические объекты бесполезны при рекурсивном построении списков объектов. Среда выполнения не позволяет назначать ICollection ‹object› типу ICollection ‹Car›, и это вполне разумно с учетом имеющейся информации. Именно здесь я пробрался в свой метод расширения ListOf, который выполняет приведение, которое неизвестно во время компиляции, и благодаря магическому механизму бокса делает возможным назначение. Вот этот опасный фрагмент кода:

И, наконец, вот пример:

Этот вывод может быть длинным, но я считаю, что он подчеркивает, сколько настроек вам придется выполнить, чтобы добиться такого поведения вручную. Кроме того, теперь у вас есть полный список владельцев, и это, вероятно, поможет вам снизить цену на пару сотен.

Большинство деталей было опущено, чтобы быть максимально сжатыми. Исходный код можно найти по адресу https://github.com/pavisalavisa/SharpenUp01.

Я надеюсь, что добавление числа и объявление серии сообщений заставят меня посвятить себя написанию и позволят мне научиться чему-то самому, если не учить других по различным темам.