Тестовий блок - особливо в C ++ - вимагає від коду, що перевіряється, додати більше швів, які були б суворо задіяні для даної проблеми.
Тільки якщо ви не вважаєте тестування невід'ємною частиною вирішення проблеми. Для будь-якої нетривіальної проблеми це повинно бути не тільки в світі програмного забезпечення.
У апаратному світі це дізналися давно - важким шляхом. Виробники різного обладнання протягом століть дізналися від незліченних падаючих мостів, вибуху автомобілів, куріння процесорів тощо., Що ми вивчаємо зараз у світі програмного забезпечення. Усі вони створюють «зайві шви» у своїх продуктах, щоб зробити їх відчутними. Більшість нових автомобілів сьогодні мають діагностичні порти для ремонтників, щоб отримати дані про те, що відбувається всередині двигуна. Значна частина транзисторів на кожному процесорі служить діагностичним цілям. У апаратному світі кожен шматочок «зайвих» речей коштує, а коли продукт виготовляється мільйонами, ці витрати, безумовно, становлять великі суми грошей. Все-таки виробники готові витратити всі ці гроші на доказовість.
Повернувшись до світу програмного забезпечення, C ++ справді складніше перевірити, ніж пізніші мови, що демонструють динамічне завантаження класів, рефлексію тощо. Тим не менш, більшість питань можна принаймні пом'якшити. У одному проекті C ++, де я використовував тестові одиниці, ми не виконували тести так часто, як ми, наприклад, в проекті Java, але все-таки вони були частиною нашої побудови CI, і ми вважали їх корисними.
Чи спосіб, який вимагає тестування одиничних тестів, щоб структурувати код програми "тільки", вигідний для одиничних тестів, чи це фактично вигідно структурі додатків?
На мій досвід, тестова конструкція вигідна загалом, а не "лише" для самих одиничних тестів. Ці переваги існують на різних рівнях:
- Здійснення тестування вашого дизайну змушує згуртовувати вашу програму на невеликі, більш-менш незалежні частини, які можуть впливати один на одного обмеженими та чітко визначеними способами - це дуже важливо для довгострокової стабільності та ремонтопридатності вашої програми. Без цього код має тенденцію до погіршення коду спагетті, коли будь-яка зміна, внесена в будь-яку частину кодової бази, може спричинити несподівані наслідки у, здавалося б, не пов'язаних між собою окремих частинах програми. Що, безсумнівно, - це кошмар кожного програміста.
- Написання самих тестів в режимі TDD насправді виконує ваші API, класи та методи, і служить дуже ефективним тестом для визначення того, чи має ваш дизайн сенс - якщо писати тести проти та інтерфейс відчуває себе незручно чи важко, ви отримуєте цінний ранній відгук, коли він все ще легко формувати API. Іншими словами, це захищає вас перед публікацією своїх API раніше.
- Шаблон розвитку, що застосовується TDD, допомагає вам зосередитись на конкретній задачі, яку потрібно виконати, і тримає вас на цілі, мінімізуючи шанси на те, що ви не будете вирішувати інші проблеми, ніж ті, що вам належить, додаючи зайві додаткові функції та складність тощо.
- Швидкий зворотний зв'язок одиничних тестів дозволяє сміливо рефакторинг коду, що дозволяє вам постійно адаптувати та розвивати дизайн протягом усього життя коду, тим самим ефективно запобігаючи ентропії коду.
Я пам'ятаю правило, в якому сказано, що не узагальнювати, поки не потрібно / поки не буде друге місце, яке використовує код. За допомогою модульних тестів завжди є друге місце, яке використовує код - а саме тест на одиницю. Тож чи достатньо цієї причини для узагальнення?
Якщо ви зможете довести, що ваше програмне забезпечення робить саме те, що потрібно робити, - і довести це досить швидко, повторювано, дешево і досить детерміновано, щоб задовольнити своїх клієнтів - без "зайвого" узагальнення або швів, вимушених одиничними тестами, перейдіть до цього (і повідомте нам, як ви це робите, тому що я впевнений, що багато людей на цьому форумі зацікавлять би мене як :-)
До речі, я припускаю, що під «узагальненням» ви маєте на увазі такі речі, як введення інтерфейсу (абстрактного класу) та поліморфізму замість одного конкретного класу - якщо ні, уточнюйте, будь ласка.