Так, SOLID - це дуже хороший спосіб розробити код, який можна легко перевірити. Як короткий буквар:
S - Принцип єдиної відповідальності: Об'єкт повинен робити саме одне і повинен бути єдиним об'єктом у кодовій базі, який робить це одне. Наприклад, візьміть клас домену, скажімо, рахунок-фактура. Клас рахунків-фактур повинен представляти структуру даних та бізнес-правила рахунків-фактур, які використовуються в системі. Це повинен бути єдиний клас, який представляє рахунок-фактуру в кодовій базі. Це може бути додатково розбито, щоб сказати, що метод повинен мати одну мету і бути єдиним методом у кодовій базі, який відповідає цій потребі.
Дотримуючись цього принципу, ви збільшуєте доказовість свого дизайну, зменшуючи кількість тестів, які ви повинні написати, які випробовують однакові функціональні можливості на різних об'єктах, а також, як правило, ви маєте менші фрагменти функціональності, які легше перевірити окремо.
O - Відкритий / закритий принцип: Клас повинен бути відкритим для розширення, але закритим для зміни . Коли об'єкт існує і працює правильно, в ідеалі не повинно виникати необхідності повертатися до нього, щоб вносити зміни, що додають нову функціональність. Натомість об’єкт повинен бути розширений або шляхом його отримання, або за допомогою підключення до нього нових або різних реалізацій залежностей, щоб забезпечити цю нову функціональність. Це дозволяє уникнути регресу; ви можете ввести новий функціонал, коли і де це потрібно, не змінюючи поведінку об'єкта, як це вже використовується в іншому місці.
Дотримуючись цього принципу, ви, як правило, збільшуєте здатність коду переносити «глузування», а також уникаєте переписувати тести, щоб передбачити нову поведінку; всі існуючі тести для об'єкта все ще повинні працювати над нерозширеною реалізацією, тоді як нові тести на нову функціональність з використанням розширеної реалізації також повинні працювати.
L - Принцип заміщення Ліскова: Клас А, залежний від класу В, повинен мати можливість використовувати будь-який X: B, не знаючи різниці. Це в основному означає, що все, що ви використовуєте як залежність, повинно мати подібну поведінку, як це бачить залежний клас. Як короткий приклад, скажімо, що у вас є інтерфейс IWriter, який відкриває Write (рядок), який реалізується ConsoleWriter. Тепер вам потрібно записати у файл, щоб ви створили FileWriter. Роблячи це, ви повинні переконатися, що FileWriter можна використовувати так само, як це робив ConsoleWriter (маючи на увазі, що єдиний спосіб залежних може взаємодіяти з ним, зателефонувавши Write (string)), і так додаткову інформацію, що FileWriter може знадобитися для цього робота (наприклад, шлях та файл для запису) має бути надана з іншого місця, ніж залежного.
Це є величезним для написання тестового коду, тому що дизайн, який відповідає LSP, може мати "глузуючий" об'єкт, заміщений реальною річчю в будь-якій точці, не змінюючи очікувану поведінку, що дозволяє перевірити невеликі шматочки коду у відриві з упевненістю що система потім працюватиме з підключеними реальними об'єктами.
Я - Принцип розділення інтерфейсу: Інтерфейс повинен мати якнайменше методів, наскільки це можливо для забезпечення функціональності ролі, визначеної інтерфейсом . Простіше кажучи, більше менших інтерфейсів краще, ніж менше великих інтерфейсів. Це пояснюється тим, що великий інтерфейс має більше причин для зміни, і викликає більше змін у інших місцях у кодовій базі, які можуть не бути необхідними.
Прихильність до ISP покращує доказовість, зменшуючи складність систем, що перевіряються, та залежності цих SUT. Якщо об'єкт, який ви тестуєте, залежить від інтерфейсу IDoThreeThings, який відкриває DoOne (), DoTwo () і DoThree (), ви повинні знущатися над об'єктом, який реалізує всі три методи, навіть якщо для об'єкта використовується тільки метод DoTwo. Але, якщо об’єкт залежить лише від IDoTwo (який виставляє лише DoTwo), ви можете легше знущатися над об’єктом, у якого є один метод.
D - Принцип інверсії залежності: Конкреції та абстракції ніколи не повинні залежати від інших конкрементів, а від абстракцій . Цей принцип безпосередньо виконує принцип нещільного з’єднання. Об'єкт ніколи не повинен знати, що таке об’єкт; натомість слід дбати про те, що робить об’єкт. Отже, використання інтерфейсів та / або абстрактних базових класів завжди слід віддати перевагу використанню конкретних реалізацій при визначенні властивостей та параметрів об’єкта чи методу. Це дозволяє обміняти одну реалізацію на іншу, не змінюючи використання (якщо ви також слідуєте за LSP, що йде рука об руку з DIP).
Знову ж таки, це величезна цінність для перевірки, оскільки вона дозволяє вам ще раз вводити макетне реалізацію залежності, а не "виробничу" реалізацію, у ваш тестований об'єкт, при цьому все ще випробовуючи об'єкт у тій формі, у якій він матиме час у виробництві. Це є ключовим для одиничного тестування "ізольовано".