Одиничне тестування декількох умов в операторі IF


26

У мене шматок коду, який виглядає приблизно так:

function bool PassesBusinessRules()
{
    bool meetsBusinessRules = false;

    if (PassesBusinessRule1 
         && PassesBusinessRule2
         && PassesBusinessRule3)
    {
         meetsBusinessRules= true;
    }

    return meetsBusinessRules;
}

Я вважаю, що для цієї конкретної функції повинно бути чотири одиничні тести. Три, щоб перевірити кожне з умов у операторі if і переконатися, що воно повертає помилкове. І ще один тест, який гарантує, що функція повертає істину.

Питання: Чи насправді замість цього має бути десять одиничних тестів? Дев'ять, що перевіряє кожен із можливих шляхів відмови. IE:

  • Неправдивий хибний хибний
  • Неправдива помилкова правда
  • Неправдива правда

І так далі для кожної можливої ​​комбінації.

Я думаю, що це надмірно, але деякі інші члени моєї команди - ні. Те, як я дивлюся на це, якщо BusinessRule1 не вдається, то він завжди повинен повертати помилкове значення, неважливо, перевірявся він перший чи останній.


Чи використовує компілятор жадібну оцінку для оператора &&?
suszterpatt

12
Якби ви написали 10 одиничних тестів, ви будете тестувати && оператор, а не ваші методи.
Мерт Аккаякая

2
Чи не було б лише вісім тестів, якби ви протестували всі можливі комбінації? Три булеві параметри увімкнено або вимкнено.
Кріс Харпер

3
@Mert: Тільки якщо ви можете гарантувати, що && завжди буде там.
Мисько

Хікі: Якщо ми витрачаємо його на написання тестів, то саме час ми не витрачаємо на щось інше. Кожному з нас потрібно оцінити, як найкраще провести час, щоб максимально досягти наших результатів як за кількістю, так і за якістю. Якщо люди думають, що витрачаючи п’ятдесят відсотків свого часу на написання тестів, це максимально покращує їх результати - добре для них. Я впевнений, що це не так для мене - я б швидше витратив цей час на роздуми над своєю проблемою. Я впевнений, що для мене це дає кращі рішення з меншою кількістю дефектів, ніж будь-яке інше використання мого часу. Поганий дизайн із повним набором тестів - це все-таки поганий дизайн.
Робота

Відповіді:


29

Формально ці типи покриття мають назви.

По-перше, є покриття предикатами : ви хочете мати тестовий випадок, який робить оператор if справжнім, і той, який робить його помилковим. Дотримання цього покриття, ймовірно, є основною вимогою для хорошого набору тестів.

Потім з'являється Покриття стану : Тут ви хочете перевірити, що кожна підзамова в системі if має значення true та false. Це, очевидно, створює більше тестів, але зазвичай виловлює більше помилок, тому часто корисно включити у свій тестовий набір, якщо у вас є час.

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

Це краще, ніж простий присудок або покриття умови? Що стосується покриття, звичайно. Але це не безкоштовно. Це дуже дорога вартість тесту на обслуговування. З цієї причини більшість людей не турбуються повним комбінаторним покриттям. Зазвичай тестування всіх гілок (або всіх умов) буде досить хорошим для лову помилок. Додавання додаткових тестів для комбінаторного тестування зазвичай не може наздогнати більше помилок, але потрібно створити та підтримувати багато зусиль. Зазвичай додаткові зусилля роблять це не вартим дуже маленької окупності, тому я б не рекомендував цього.

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


2
Якщо булеві значення передаються із зовнішніх джерел (тобто вони не завжди перевірені), часто необхідне комбінаторне умовне покриття. Спочатку складіть таблицю комбінацій. Потім для кожного запису вирішіть, чи є цей запис значущим випадком використання. Якщо ні, то десь має бути код (або програмне твердження, або пункт перевірки), щоб запобігти виконанню цієї комбінації. Важливо не збивати всі параметри в одному комбінаторному тесті: спробуйте розділити параметри на групи, які взаємодіють одна з одною, тобто ділиться однаковим булевим виразом.
rwong

Наскільки ви впевнені в жирних умовах? Ваша відповідь, здається, є єдиним випадком "охоплення комбінаторних умов", і деякі ресурси говорять про те, що "охоплення предикатами" та "умовне покриття" - це одне і те ж.
Штійн

8

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

Час OTOH для написання одиничних тестів зазвичай є дефіцитним ресурсом. Тому прагніть знайти найкращий спосіб провести обмежений час, який у вас є . Наприклад, якщо у вас є інший важливий метод з 0% охопленням, може бути краще написати пару одиничних тестів для покриття цього, а не додавати додаткові тести для цього методу. Звичайно, це також залежить від того, наскільки тендітним є виконання кожного. Планування багатьох змін цього конкретного методу в осяжному майбутньому може виправдати додаткове охоплення тесту. Тож може бути на критичному шляху всередині програми. Це все фактори, які може оцінити лише ви (команда).

Я особисто був би задоволений 4-ма тестами, які ви окреслили, тобто:

  • справжнє хибне хибне
  • false справжній false
  • false false true
  • справжній справжній правдивий

плюс, можливо, один:

  • справжнє справжнє хибне

переконатися, що єдиний спосіб отримати прибуткову вартість - trueце задоволення всіх трьох правил бізнесу. Зрештою, якщо ваші товариші по команді наполягають на покритті комбінаторних доріжок, можна додати ці додаткові тести, ніж продовжувати аргумент набагато довше :-)


3

Якщо ви хочете бути в безпеці, вам знадобиться вісім тестових одиниць, використовуючи умови, представлені трьома таблицями змінної істинності ( http://teach.valdosta.edu/plmoch/MATH4161/Spring%202004/and_or_if_files/image006.gif ).

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


2
Тестування блоку - це тестування в білій коробці.
Péter Török

Ну а порядок не має значення, && - комунікативний, або, принаймні, має бути
Zachary K

2

Так, має бути повне поєднання в ідеальному світі.

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


1
Тестування блоку - це тестування в білій коробці. І ми не живемо в ідеальному світі.
Péter Török

@ PéterTörök - Ми не живемо в ідеальному світі, щоб бути впевненим, але stackexchange не погоджується з тобою з іншого боку. Спеціально для TDD тести записуються на технічні умови, а не на реалізацію. Я особисто приймаю "специфікацію", щоб включити всі входи (включаючи змінні елементи) та всі результати (включаючи побічні ефекти).
Теластин

1
Це лише один конкретний потік StackOverflow, про конкретний випадок, який не слід надмірно генералізувати. Тим більше, що ця публікація, очевидно, стосується тестування коду, який вже написаний.
Péter Török

1

Держава - зло. Наступна функція не потребує одиничного тесту, оскільки вона не має побічних ефектів і добре розуміє, що робить, а що не робить. Навіщо це тестувати? Ви не довіряєте своєму власному мозку ??? Статичні функції чудові!

static function bool Foo(bool a, bool b, bool c)
{
    return a && b && c;
}

2
Ні, я не довіряю своєму власному мозку - я навчився важкого способу завжди двічі перевіряти те, що роблю :-) Тому мені все одно знадобляться одиничні тести, щоб переконатися, що я нічого не вводив, наприклад, і нічого не збирався щоб зламати код у майбутньому. І ще модульні тести , щоб перевірити метод абонента , який обчислює стан , представлене a, bі c. Ви можете переміщати ділову логіку будь-яким способом, зрештою, вам все одно потрібно десь перевірити її.
Péter Török

@ Péter Török, ви також можете робити помилки в своїх тестах і, таким чином, виявляти помилкові позитиви, тож де зупинитись? Ви пишете одиничні тести для своїх одиничних тестів? Я не довіряю своєму мозку також на 100%, але наприкінці дня написання коду - це те, чим я заробляю на життя. У цій функції можлива помилка, але важливо писати код таким чином, щоб помилку було легко простежити до джерела, і коли ви виділили проблему та зробили виправлення, вам краще . Добре написаний код може розраховувати на інтеграційні тести здебільшого infoq.com/presentations/Simple-Made-Easy
робота

2
Дійсно, тести теж можуть бути несправними. (TDD вирішує це, роблячи тести спочатку невдалими.) Однак, помилка, що робиться один і той же тип двічі (і не помічається), має ймовірність значно меншою. Загалом, жодна кількість та тип тестування не можуть довести, що програмне забезпечення відсутнє помилок, просто зменшіть ймовірність помилок до прийнятного рівня. І в швидкості відстеження помилок до джерела, IMO ніщо не може перемогти одиничні тести - швидкий зворотний зв'язок rulez :-)
Péter Török

"Наступна функція не потребує одиничного тесту". Я думаю, що ви тут саркастичні, але це не ясно. Чи довіряю я власному мозку? НІ! Чи я довіряю мозку наступного хлопця, який торкнеться коду? НІКОЛИ БІЛЬШЕ НІ! Я вірю, що всі припущення, що стоять за кодом, будуть справдими через рік? ... ви отримаєте мій дрейф. Також статичні функції вбивають OO ... якщо ви хочете робити FP, тоді використовуйте мову FP.
Роб

1

Я знаю, що це питання досить старе. Але я хочу дати ще одну точку зору на проблему.

По-перше, ваші одиничні тести повинні мати дві цілі:

  1. Створіть документацію для вас та ваших товаришів по команді, щоб через певний проміжок часу ви змогли прочитати одиничний тест і переконатися, що ви розумієте what's the class' intentionтаhow the class is doing its work
  2. Під час розробки модульний тест гарантує, що код, який ми записуємо, виконує свою роботу так, як це було призначено нашим розумом.

Отже, рекапітуючи проблему, ми хочемо протестувати a complex if statement, для даного прикладу є 2 ^ 3 можливості, тобто важлива кількість тестів, які ми можемо написати.

  • Ви можете адаптуватися до цього факту і записати 8 тестів або скористатися параметризованими тестами
  • Ви також можете слідувати за іншими відповідями і пам’ятати, що тести повинні бути чіткими з наміром, таким чином ми не збираємося возитися з занадто великою кількістю деталей, які в найближчому майбутньому можуть ускладнити розуміння what is doing the code

З іншого боку, якщо ви знаєте, що ваші тести ще складніші за впровадження, це тому, що реалізація повинна бути перероблена (більш-менш залежно від випадку), а не сам тест.

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

If some simple business rule apply, derive to the next handler

Наскільки просто було б перевірити різні кілька простих правил, а не складне правило?

Сподіваюся, це допоможе,


0

Це один із тих випадків, коли щось на зразок швидкої перевірки ( http://en.wikipedia.org/wiki/QuickCheck ) стане вашим другом. Замість того, щоб виписувати всі N випадків вручну, комп'ютер змусить генерувати всі (або принаймні велику кількість) можливих тестових випадків і підтвердити, що всі вони приносять чудовий результат.

Ми програмуємо комп’ютери для життя на цьому, чому б не запрограмувати комп'ютер для створення тестових випадків для вас?


0

Ви можете переробити умови на умови охорони:

if (! PassesBusinessRule1) {
    return false;
}

if (! PassesBusinessRule2) {
    return false;
}

if (! PassesBusinessRule3) {
    return false;
}

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

(Зверніть увагу, що я великий вентилятор "єдиної точки виходу", але я роблю виняток для умов охорони. Але є й інші способи структурувати код, щоб у вас не було окремих повернень.)

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