Вибачте за некро в цій публікації, але я змушений зважитися на пару речей, які, здається, не торкалися.
По-перше, головне - коли ми виявляємо потребу в доступі до приватних членів на уроці під час тестування підрозділів, це, як правило, великий, товстий червоний прапор, який ми піддали стратегічному чи тактичному підходу і ненавмисно порушили єдину головну відповідальність, натискаючи поведінку там, де вона не належить. Відчуття необхідності доступу до методів, які насправді є не що інше, як ізольована підпрограма будівельної процедури - одне з найпоширеніших випадків цього; однак, це схоже на те, що ваш начальник очікує, що ви з'явитесь на роботу, готову до роботи, а також маючи пекельну потребу знати, через яку ранкову програму ви пройшли, щоб перейти до цього стану ...
Інший найпоширеніший екземпляр цього явища - це те, коли ти опиняєшся перевірити прислів’я "клас богів". Сама по собі це особлива проблема, але вона страждає тим самим основним питанням, коли потрібно знати інтимні деталі процедури - але це не виходить із теми.
У цьому конкретному прикладі ми ефективно поклали відповідальність за повну ініціалізацію об'єкта Bar конструктору класу FooBar. У об'єктно-орієнтованому програмуванні одна з основних прихильників полягає в тому, що конструктор є «священним» і його слід захищати від недійсних даних, що призведе до недійсності його власного внутрішнього стану та залишить його зафіксованим до відмови деінде вниз за течією (що може бути дуже глибоким) трубопровід.)
Нам тут цього не вдалося, дозволивши об’єкту FooBar прийняти смугу, яка не готова до того часу, коли FooBar будується, і компенсували своєрідним "злому" об'єкта FooBar, щоб взяти питання у свої власні. руки.
Це є наслідком відмови від дотримання іншого об'єктно-орієнтованого програмування (у випадку з Bar), що полягає в тому, що стан об'єкта повинен бути повністю ініціалізований і готовий обробляти будь-які вхідні дзвінки до його публічних членів одразу після створення. Тепер це не означає одразу після виклику конструктора у всіх випадках. Якщо у вас є об'єкт, який має багато складних сценаріїв побудови, тоді краще виставити сетерів для його необов'язкових членів об’єкту, який реалізується відповідно до схеми створення дизайну (Factory, Builder тощо). останні випадки,
У вашому прикладі властивість "статусу" Bar не здається в дійсному стані, в якому FooBar може його прийняти - тому FooBar робить щось для того, щоб виправити цю проблему.
Друге питання, яке я бачу, це те, що, здається, ви намагаєтеся перевірити свій код, а не практикувати тестові розробки. Це, безумовно, моя власна думка на даний момент часу; але цей тип тестування дійсно є антидіаграмою. Що ви в кінцевому підсумку робите, потрапляєте в пастку розуміння того, що у вас є основні проблеми дизайну, які не дозволяють вашому коду перевірятись після цього факту, а не писати потрібні вам тести та згодом програмувати на тести. У будь-якому випадку, якщо ви зіткнетеся з проблемою, вам слід все-таки закінчити однакову кількість тестів і рядків коду, якби ви справді досягли реалізації SOLID. Отже - навіщо намагатися інженеру повернути свій шлях до перевіряемого коду, коли ви можете просто вирішити цю проблему на початку ваших зусиль з розвитку?
Якби ви це зробили, то ви б набагато раніше зрозуміли, що вам доведеться написати якийсь досить прискіпливий код, щоб перевірити свій дизайн, і ви мали б можливість на початку переосмислити свій підхід, переклавши поведінку на реалізацію, що легко перевіряються.