Програмування на основі контракту та тест на одиницю


13

Я дещо захисний програміст і великий прихильник контрактів Microsofts Code.

Тепер я не завжди можу використовувати C #, і в більшості мов єдиним інструментом, який я маю, є твердження. Тому я зазвичай закінчую такий код:

class
{       
    function()
    {   
         checkInvariants();
         assert(/* requirement */);

         try
         {
             /* implementation */
         }
         catch(...)
         {
              assert(/* exceptional ensures */);                  
         }
         finally
         {
              assert(/* ensures */);
              checkInvariants();
         }
    }

    void checkInvariants()
    {
         assert(/* invariant */);
    }
}

Однак ця парадигма (або як би ви її не назвали) призводить до великої захаращеності коду.

Я почав замислюватися, чи дійсно варто докладати зусиль і чи належним чином тест на одиницю вже це покриє?


6
Хоча одиничні тести дозволяють висунути твердження з коду програми (і, отже, уникати захаращеності), врахуйте, що вони не можуть перевірити все, що може статися в реальній виробничій системі. Таким чином, договори з кодом IMO мають деякі переваги, особливо для критичного коду, де правильність особливо важлива.
Джорджіо

Отже, це в основному час розробки, ремонтопридатності, читабельності та кращого покриття коду?
ronag

1
Я в основному використовую твердження в коді, щоб перевірити правильність параметрів (наприклад, null), а в тесті одиниць додатково перевірити ці твердження.
artjom

Відповіді:


14

Я не думаю, що ви повинні думати про це як "проти".
Як зазначається в коментарі @Giorgio, кодові договори повинні перевіряти інваріанти (у виробничому середовищі), а одиничні тести - переконайтесь, що код працює так, як очікувалося, коли ці умови будуть виконані.


2
Я думаю, що також важливо перевірити, чи працює код (наприклад, він кидає виняток), коли умови не виконуються.
svick

6

Контракти допомагають вам принаймні з одним, що не відповідає одиничним тестам. Коли ви розробляєте загальнодоступний API, ви не можете перевірити, як люди використовують ваш код. Однак ви все одно можете визначити договори для своїх методів.

Я особисто ставлюся до цього строго щодо договорів лише тоді, коли маємо справу з публічним API модуля. У багатьох інших випадках це, мабуть, не варто докладати зусиль (і замість цього можна використовувати одиничні тести), але це лише моя думка.

Це не означає, що я раджу не думати про контракти в тих випадках. Я завжди думаю про них. Я просто не думаю, що потрібно завжди чітко їх кодувати.


1

Як вже було сказано Контракти та одиничні випробування мають різну мету.

Контракти стосуються оборонного програмування, щоб переконатися, що виконуються передумови, код викликається правильними параметрами тощо.

Блок тестів для забезпечення роботи коду в різних сценаріях. Це як "специфікації з зубами".

Твердження добре, що вони роблять код надійним. Однак якщо ви переживаєте, що він додає багато коду, ви також можете додати умовні точки перерви в деяких місцях під час налагодження та зменшити кількість оцінок.


0

Все, що у вас є у ваших викликах checkVariants (), можна зробити з тестування, скільки зусиль, які насправді можуть бути, залежить від багатьох речей (зовнішні залежності, рівні з’єднання тощо), але це очистить код з однієї точки зору. Наскільки тестова була б база коду, розроблена проти тверджень, без певного рефакторингу, я не впевнений.

Я погоджуюся з @duros, це не слід розглядати як ексклюзивні чи конкуруючі підходи. Насправді в середовищі TDD ви навіть можете стверджувати, що для тверджень про «вимогу» потрібно буде провести тести :).

Однак стверджує, що НЕ робіть код більш надійним, якщо ви дійсно не зробите щось для виправлення невдалої перевірки, вони просто зупиняють пошкодження даних або подібне, як правило, припиняючи обробку при перших ознаках проблеми.

Тестово розроблене / добре перевірене рішення, як правило, вже замислювалося та / або виявило багато джерел / причин поганих входів та виходів під час розробки взаємодіючих компонентів і вже розглядало їх ближче до джерела проблеми.

Якщо ваше джерело зовнішнє і ви не маєте контролю над ним, щоб уникнути захаращення коду, вирішуючи інші проблеми з кодами, ви можете розглянути можливість впровадження якогось компонента очищення / затвердження даних між джерелом та вашим компонентом і поставити там свої чеки .

Також мені цікаво, на яких мовах у вашому користуванні немає такого роду xUnit чи іншої бібліотеки для тестування, яку хтось розробив, я вважав, що в ці дні є щось багато?


0

На додаток до тестових одиниць та кодових контрактів, я просто думав, що я виділяю ще один аспект, який полягає у визначенні ваших інтерфейсів, таким чином, щоб ви усунули або зменшили можливість виклику коду неправильно в першу чергу.

Це не завжди просто чи можливо, але, безумовно, варто задати собі питання: "Чи можу я зробити цей код більш надійним?"

Андер Хейлсберг, творець C #, сказав, що однією з найбільших помилок у C # було не врахування нерегульованих посилальних типів. Це одна з головних причин настільки необхідного захаращення коду охорони.

Тим не менш, рефакторинг, щоб мати лише необхідну і достатню кількість захисного коду, робить, на мій досвід, більш корисним і доступним кодом.

Погодьтеся з @duros про решту.


0

Зробіть і те, і інше, але зробіть кілька статичних помічників, щоб уточнити свої наміри. Це те, що Google зробив для Java, перегляньте code.google.com/p/guava-libraries/wiki/PreconditionsПояснено

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.