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


27

Будь ласка, дивіться код нижче; вона перевіряє, чи може людина, яка має стать жінки, має право на пропозицію1:

[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
    var personId = Guid.NewGuid();
    var gender = "F";
    var person = new Person(personId, gender);

    var id = Guid.NewGuid();
    var offer1 = new Offer1(id,"Offer1");
    Assert.False(offer1.IsEligible(person));
}

Цей одиничний тест успішний. Однак це не вдасться, якщо "Offer1" буде запропоновано жінкам у майбутньому.

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

update Offers set Gender='M' where offer=1;

а в деяких випадках у такій доменній моделі:

if (Gender=Gender.Male)
{
  //do something
}

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


2
Подумайте з іншого ракурсу: чи хочете ви тести, які не пройшли, коли ви змінюєте логіку в системі під тестом?
Фабіо

Відповіді:


77

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

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

Назва тесту Returns False When Given A Person With A Gender Of Femaleне описує бізнес-правила. Правило в бізнесі було б щось подібне Offers Applicable to M should not be applied to persons of gender F.

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


@JaquesB, то це не було б одиничним тестом? чи це було б? Я вважаю, що це було б тестом на інтеграцію, якщо б була задіяна база даних. Це так? Ви говорите, не використовуйте одиничні тести, якщо бізнес-логіка сильно зміниться?
w0051977

@ w0051977: Залежить, як ви пишете тест. Якщо тест включає фактичну зміну чогось змінити в базі даних, то це буде тест на інтеграцію.
ЖакБ

3
@ w0051977 Краща ідея - не потрібно, щоб сховище було залежним від компонента, відповідального за впровадження бізнес-правил. Майте оркестрацію вищого рівня, яка викликає сховище, а потім викликає бізнес-правила. Тепер ви можете перевірити ділові правила у відриві.
Мураха P

5
@ w0051977 Звичайно, це - тести визначають поведінку. Якщо правила, що регулюють поведінку компонента, змінюються, то тести повинні змінюватися, щоб відобразити зміну поведінки. Те, що не повинно змінювати, - це тести, які визначають поведінку, відмінне від того, що змінюється. Якщо поведінка визначається базою даних, то тест, що охоплює якийсь інший код, за своєю суттю не пов'язаний, і його не потрібно змінювати, якщо ця логіка бази даних не входить у рамки тесту. Цей обсяг ви самі маєте визначити, і семантика того, чи є це тест одиниці чи інтеграційний тест, насправді не важлива.
Мураха P

3
@ w0051977 дещо розширивши цю ідею, якщо зміниться бізнес-логіка або виправлено помилку, і тести не потребують коригування, це знак того, що тести не охоплюють достатню кількість випадків і їх, як правило, слід розширити.
Морген

14

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

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

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

Якщо ви писали одиничний тест, ви створили б personі offer1з нуля, не покладаючись на стан бази даних. Щось на зразок

[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
    var personId = Guid.NewGuid();
    var gender = "F";
    var person = new Person(personId, gender);

    var id = Guid.NewGuid();
    var offer1 = new Offer1(id, "ReturnsFalseWhenGivenAPersonWithAGenderOfFemale");
    offer1.markLimitedToGender("M");

    Assert.False(offer1.IsEligible(person));
}

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

Ви можете створити та налаштувати базу даних як частину тесту. У C #, використовуючи NUnit, або в JUnit Java, ви б створили базу даних Setupметодом. Імовірно, ваша тестова структура має подібне поняття. У цьому методі ви можете вставляти записи в базу даних за допомогою SQL.

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

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

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

TL; DR : ви можете писати такі тести, але вам може бути краще писати програмне забезпечення, так що вам не доведеться цього робити.


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

У початковій публікації немає жодних вказівок, що задіяна база даних. Тому твердження, що він передбачає, що Offer1 вже є в базі даних, є химерним.
Вінстон Еверт

2
@WinstonEwert: є чітка вказівка, вам потрібно уважніше прочитати питання. Я не усвідомлював це також у першому читанні, але це дійсно те, про що йдеться в ОП.
Док Браун

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