Чи є якесь значення в написанні одиничного тесту, що є підмножиною іншого тесту?


15

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

def test_length():
    result = my_function()
    assert len(result) == 2

def test_order()
    a, b = my_function()
    assert a < b

Тут, якщо test_lengthне вдасться, то test_orderі провал. Це найкраща практика писати test_lengthчи пропускати?

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

- це дублікат вищевказаного.



2
@ GlenH7 - це здається іншим питанням. Інший - "якщо у вас є функції, де Aдзвонить Bі повертає один і той же результат, ви повинні перевірити і те, Aі B". Йдеться більше про те, що тести перекриваються, а не функції, що перевіряються. (Хоча це заплутано, як їх зараз називають).
Теластин


1
Власне кажучи, ці тести насправді не перетинаються (вони не мають залежності від успіху). Функція lambda: type('', (), {'__len__': lambda self: 2})()передасть перше, а не друге.
liori

1
@ GlenH7: FWIW, я не дуже змінив питання, просто спробував зробити його безпечним для гната ;-) (@gnat: не ображайтесь, просто жартую!)
Doc Brown

Відповіді:


28

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

У прикладі я об'єднав би два тести разом. Так, це означає, що у вас є кілька тверджень. Дуже погано. Ви все ще тестуєте одну річ - результат функції. Іноді в реальному світі це означає зробити дві перевірки.


Я підтримав вашу відповідь, хоча вона пропускає одну незначну точку. У Python другий тест також вийде з ладу, коли my_functionне поверне рівно два значення без будь-якого твердження - тому що присвоєння призведе до виключення. Тож насправді не потрібно використовувати кілька тверджень і два чеки для перевірки одного і того ж.
Док Браун

@DocBrown - Я припустив, що стільки, але я не знайомий з повідомленнями про помилки Python, щоб знати, чи може бути корисним наявність помилки утвердження замість випадкового винятку / помилки з інформативних причин.
Теластин

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

5
@DocBrown Інше значення при явній перевірці з твердженням полягає в тому, що кожному, хто перевіряє тест, стає зрозуміло, що це збій тестуваного коду, а не сам тест. Коли мої тести стикаються з несподіваними винятками, мені завжди доводиться витрачати деякий час, з'ясовуючи, який з них насправді не так.
Кріс Хейс

@ChrisHayes: Я написав "немає потреби", не "немає значення".
Док Браун

5

Ваші тести повинні бути явними. Не зовсім зрозуміло, що якщо text_length не вдається тест_order не вдається.

Я не впевнений, як це відбувається в Python, який ви опублікували, але якщо len(result)це 3, то перший не вдасться, але другий може пройти (а якщо не в Python, то на таких мовах, як JavaScript).

Як ви сказали, ви хочете перевірити, що функція повертає два числа і що вони в порядку. Два тести це.


1
It's not completely inferred that if text_length fails test_order fails- в Python, це, дасть вам виняток.
Док Браун

Я думаю, що питання стосується випадку, коли невдача test_lengthпередбачає провал test_order. Той факт, що аналогічна пара тестів, написаних на Javascript, не поводиться так само, як ці два тести python, начебто не має значення.
Давуд каже, що повернемо Моніку

2
@DavidWallace: пам'ятайте, питання було "Чи найкраща практика писати test_length чи пропустити його"? У Javascript вам потрібні обидва тести, щоб переконатися, що ви не пропустили проблему (коли ви не об’єднаєте два тести в один). У Python ви можете сміливо опустити перше (що в першому реченні цієї відповіді заперечується, а в другому оголошено як "я не впевнений"). Чесно кажучи, хороша відповідь виглядає інакше. Однак я не спростував цю відповідь, оскільки хороша частина насправді є згадуванням JavaScript.
Док Браун

4
@DavidWallace: оскільки ми тут програміст.com, а не на stackoverflow.com, IMHO давати відповідь, яку можна застосувати до декількох мов, краще, ніж відповідь лише для певної мови. Але коли йдеться про певну мову, відповідь має бути правильною щодо мови, а не змішувати деякі властивості.
Док Браун

1
Справа в тому, що питання "чи варто написати тест, який є підмножиною іншого тесту", і ця відповідь говорить, "в деяких мовах жоден з ваших тестів не є набором інших", а потім дійшов до висновку, що обидва тести є тому необхідно. Він читає мені так, ніби хтось сказав: "Ваш код взагалі не компілюється в C ++, а крім того, у C ++ функція може повернути лише одне значення, тому вам не потрібно тестувати, вона повертає два. Лише один тест". ;-)
Стів Джессоп

2

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

Тож справді зайвим є обидва ці тести. Тримайте лише, test_orderале подумайте про його перейменування test_length_and_order.

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


1
testБородавка має сенс тестової структури Python. Що, звичайно, не потрібно змінювати, чи ви фанат цього, але змінює вагу аргументу, необхідного для того, щоб хтось його не використовував ;-)
Стів Джессоп

@SteveJessop Так, я постійно забуваю, що це потрібно. Коли я писав тести Python деякий час тому, я ввійшов у звичку починати їх усі test_that_, як- небудь test_that_return_values_are_in_orderтощо. Можливо, майбутня версія тестової рамки якось обійдеться з цією вимогою.
Давуд каже, що повернемо Моніку

@DavidWallace: ви можете змінити префікс, якщо хочете.
Лі Лі Раян

1

Я б залишив ці тести окремо, якщо саме так вони розвивалися. Так test_order, швидше за все, не вдасться test_length, але ви точно знаєте чому.

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

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

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

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

Тож я б, мабуть, почав з ваших окремих тестів і розширювався test_lengthб test_length_and_typesі залишав їх test_orderокремими, припускаючи, що останні вважаються "нормальною обробкою".

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