Тестовий приклад іменування найкращих практик [закрито]


564

Які найкращі практики називати одиничні тестові класи та методи тестування?

Про це йшлося раніше в розділі SO, на якій основі є популярні умови іменування для Unit Tests?

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

Тоді у своїх тестових класах у мене є методи із назвами методів, які я тестую, підкреслення, а потім ситуація та те, що я очікую, що відбудеться, наприклад Save_ShouldThrowExceptionWithNullName().



1
Це не відповідає на ваше запитання, але варто прочитати: haacked.com/archive/2012/01/02/structuring-unit-tests.aspx
Robs

3
Посібник зі стилів Google говорить: test<MethodUnderTest>_<state>напр., testPop_emptyStack Google-styleguide.googlecode.com/svn/trunk/javaguide.html 5.2.3 Назви методів. Якщо ви сумніваєтесь, слідкуйте за Google.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

2
@CiroSantilli 六四 事件 法轮功 包 卓 轩 І наступне речення говорить: "Немає одного правильного способу назви методів тестування". Піди розберися.
користувач2418306

1
Я все ще віддаю перевагу рекомендації Філа Хакка навіть через роки.
pimbrouwers

Відповіді:


524

Мені подобається стратегія іменування Роя Ошерова , вона така:

[UnitOfWork_StateUnderTest_ExpectedBehavior]

У ньому є вся необхідна інформація про назву методу та структуровано.

Одиниця роботи може бути такою ж маленькою, як один метод, клас або такою ж великою, як кілька класів. Він повинен представляти всі речі, які підлягають випробуванню в цьому тестовому випадку та є під контролем.

Для складання я використовую типове .Testsзакінчення, яке, на мою думку, є досить розповсюдженим і однаковим для класів (закінчується на Tests):

[NameOfTheClassUnderTestTests]

Раніше я використовував Fixture як суфікс замість Tests, але я думаю, що останній є більш поширеним, потім я змінив стратегію іменування.


228
Для мене немає сенсу ставити назву методу в тестовий метод. Що робити, якщо Ви перейменовуєте метод? Жоден інструмент рефакторингу не перейменовує тести для вас. Зрештою, ви перейменовуєте методи тестування вручну або, швидше за все, неправильно назвали тести. Це як з коментарями. Набагато гірше, ніж взагалі не коментувати код.
Пьотр Перак

80
@Peri, я думаю, що це компроміс. З одного боку, назви ваших тестів можуть застаріти, а з іншого - ви не можете сказати, яким методом тестується ваш тест. Я вважаю, що остання зустрічається набагато частіше.
Джоел МакБет

15
Щоб додати коментар Пері - всі методи відповідають за певні дії, наприклад UpdateManager.Update(). Маючи це на увазі, я схильний називати свої тести WhenUpdating_State_Behaviourабо WhenUpdating_Behaviour_State. Таким чином я перевіряю певну дію класу, уникаючи при цьому імені методу в імені тесту. Але найважливіше - я маю зрозуміти, яка бізнес-логіка провалюється, коли бачу ім'я невдалого тесту
Рамунас,

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

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

121

Мені подобається дотримуватися стандарту іменування "Слід" для тестів , називаючи прилад для тестування після тестового блоку (тобто класу).

Для ілюстрації (використовуючи C # та NUnit):

[TestFixture]
public class BankAccountTests
{
  [Test]
  public void Should_Increase_Balance_When_Deposit_Is_Made()
  {
     var bankAccount = new BankAccount();
     bankAccount.Deposit(100);
     Assert.That(bankAccount.Balance, Is.EqualTo(100));
  }
}

Чому "Слід" ?

Я вважаю, що це змушує письменників-тестів назвати тест реченням у рядку "Чи повинен [бути в якомусь стані] [після / до / коли] [дія відбувається]"

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

Оновлення :

Я помітив, що Джиммі Богард також є шанувальником "слід" і навіть має тестову бібліотеку під назвою Should .

Оновлення (4 роки потому ...)

Для тих, хто цікавиться, мій підхід до іменування тестів змінювався роками. Одне з питань, пов’язаних із шаблоном Should, я описую вище, як його не просто зрозуміти з першого погляду, який метод перевіряється. Для OOP я думаю, що має сенс починати ім'я тесту з методу, який перевіряється. Для добре розробленого класу це повинно спричинити читабельні назви методів тестування. Зараз я використовую формат, подібний до <method>_Should<expected>_When<condition>. Очевидно, залежно від контексту, ви можете замінити дієслова Should / When на щось більш відповідне. Приклад: Deposit_ShouldIncreaseBalance_WhenGivenPositiveValue()


32
Може бути , навіть краще і менш багатослівні, просто написати пропозицію , яке говорить , що він робить, припускаючи , що тестові роботи: increasesBalanceWhenDepositIsMade().
hotshot309

3
Нещодавно побачив статтю, в якій згадується аналогічна конвенція про іменування (хотілося б, щоб я її зробив у закладках). Призначений для того, щоб зробити списки тестів дуже читабельними при сортуванні за тестовим кріпленням. Ви бачите щось на кшталт "BankAccount", а потім під ним (у різних рядках) "Should_Increase_Balance_When_Deposit_Is_Made" "Should_Decrease_Balance_When_Withdrawal_Is_Made" і т.д.
Саймон Тевсі

Знайшов статтю. Це в кодексі Джастіна Етередже. Подуманий блог Початок глузування з Moq 3 - Частина 1 .
Саймон Тевсі

11
Я також використовую Should and When, але навпаки. наприклад, WhenCustomerDoesNotExist_ShouldThrowException (). Для мене це має набагато більше сенсу, ніж тоді, коли тоді (тобто в певному сценарії повинен бути певний очікуваний результат). Це також вписується в AAA (Упорядкувати, діяти, потверджувати) ...
Асирт

2
@Schneider: враховуючи "слід" = "рекомендовано", то необов'язково, мені цікаво: чи не було б лексично краще використовувати "повинен" = "повинен" тоді потрібно / обов'язково. Наприклад, RFC робить різницю між обома. Тож рекомендується чи потрібно здати тести?
blackwizard

79

Мені подобається такий стиль називання:

OrdersShouldBeCreated();
OrdersWithNoProductsShouldFail();

і так далі. Це неправдиво дає зрозуміти, у чому проблема.


63
але @ hotshot309, можливо, він використовує .NET - .NET Конвенції про капіталізацію
Ace

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

3
@CoffeeAddict, оскільки підкреслення в ідентифікаторах є <del> аберацією </del>, не дуже ідіоматичною в C #
Sklivvz

2
Я також хотів би уникнути використання shouldя вважаю за краще willтакOrdersWithNoProductsWillFail()
Калин

4
@Calin На мою думку, використання Willнасправді не є доцільним, і, таким чином, ти насправді помилково кажеш читачеві, що жодним чином тест не вийде з ладу ... якщо ти використаєш, Willщоб висловити щось у майбутньому, що може не статися, ти неправильне використання, тоді як Shouldтут кращий вибір, оскільки він вказує на те, що ви хочете / хочете, щоб щось сталося, але це не відбулося чи не вдалося, коли тест запускається, він говорить вам, чи не вдалося / вдалося, так що ви не можете наслідувати це заздалегідь, це логічне пояснення цьому, що ваше? чому ти уникаєш Should?
Еял Сольник

51

Кент Бек пропонує:

  • Один тестовий прилад на «одиницю» (клас вашої програми). Тестові світильники - це самі заняття. Назва тестового кріплення має бути:

    [name of your 'unit']Tests
    
  • Тести (методи випробування кріплення) мають такі назви:

    test[feature being tested]
    

Наприклад, маючи такий клас:

class Person {
    int calculateAge() { ... }

    // other methods and properties
}

Тестовим пристосуванням було б:

class PersonTests {

    testAgeCalculationWithNoBirthDate() { ... }

    // or

    testCalculateAge() { ... }
}

4
Я б хотів, щоб більше людей дотримувалися цих вказівок. Не так давно мені довелося перейменовувати більше 20 методів тестування, оскільки вони мали такі назви, як "ATest", "BasicTest" або "ErrorTest".
Клин

85
чи не стає префікс методу 'test' надмірним з огляду на суфікс класу?
Гевін Міллер

50
Пам'ятайте, що коли Кент написав цю книгу. Атрибути не були винайдені. Тому ім'я Test у назві методу вказувало тест-рамці, що метод був тестом. Також багато трапляються з 2002 року
Томас Йесперсен

14
testCalculateAge ... це безглузда назва для вашого методу тестування. "test" є зайвим (ви називаєте всі свої методи префіксом "method"?) У решті назви немає випробуваної умови чи того, що очікувалося. Чи
обчислюється

1
Хочу додати, що при використанні цієї стратегії необхідна документація для уточнення очікуваного результату. В якості побічної примітки про префікс 'test'; деякі рамки тестування одиниць вимагають конкретних префіксів або суфіксів для розпізнавання тестів. Префіксація абстрактних класів за допомогою "Анотація" не вважається зайвою (тому що це самодокументування), тому чому це не стосується тесту "Тест"?
siebz0r

17

Назви класів . Щодо імен кріпильних тестів, я вважаю, що "Тест" досить поширений у всюдисущій мові багатьох доменів. Наприклад, в інженерній галузі: StressTestі в області косметики: SkinTest. Вибачте, що не погоджуюся з Кентом, але використання "Тесту" у моїх тестових пристосуваннях ( StressTestTest?) Заплутано.

"Unit" також багато використовується в доменах. Напр MeasurementUnit. Клас називається MeasurementUnitTestтестом "Measurement" або "MeasurementUnit"?

Тому я люблю використовувати префікс "Qa" для всіх моїх тестових класів. Наприклад QaSkinTestі QaMeasurementUnit. Його ніколи не плутають з об’єктами домену, а використання префікса, а не суфікса означає, що всі тестові прилади живуть разом візуально (корисно, якщо у вашому тестовому проекті є підробки або інші класи підтримки)

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

Назви методів тестування . Мені подобається називати свої методи WhenXXX_ExpectYYY. Це робить попередню умову зрозумілою та допомагає з автоматизованою документацією (a la TestDox). Це схоже на поради в тестовому блозі Google, але з більшим розділенням передумов та очікувань. Наприклад:

WhenDivisorIsNonZero_ExpectDivisionResult
WhenDivisorIsZero_ExpectError
WhenInventoryIsBelowOrderQty_ExpectBackOrder
WhenInventoryIsAboveOrderQty_ExpectReducedInventory

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

12

Я використовую концепцію Дано-Коли-Тоді . Погляньте на цю коротку статтю http://cakebaker.42dh.com/2009/05/28/given-when-then/ . У статті описано це поняття з точки зору BDD, але ви можете використовувати його і в TDD без будь-яких змін.


Дано-Коли-Тоді те саме, що MethodName_Scenario_ExpectedBehavior, чи не так ?!
Світло

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

1
"Дано, коли тоді" часто називають Геркіном. Це DSL, який вийшов із інструментів «Огірок», «JBehave» та «Behat».
bytedev

+1 це найкращий метод imo. Розв’язання того, як метод робить щось із того, що ви очікуєте, буде результатом, дуже потужне і дозволяє уникнути безлічі проблем, описаних в інших коментарях.
Лі


7

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


7

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

Скажімо, я тестую Settingsклас в проекті в MyApp.Serializationпросторі імен.

Спочатку я створять тестовий проект із MyApp.Serialization.Testsпростором імен.

В рамках цього проекту і, звичайно, простору імен, я створити клас, який називається IfSettings(зберігається як IfSettings.cs ).

Скажімо, я тестую SaveStrings()метод. -> Я назву тест CanSaveStrings().

Коли я запускаю цей тест, він покаже наступний заголовок:

MyApp.Serialization.Tests.IfSettings.CanSaveStrings

Я думаю, що це дуже добре говорить мені, що це тестування.

Звичайно корисно, що в англійській мові іменник "Тести" є таким самим, як і дієслово "тести".

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

Зазвичай назви тестів повинні починатися з дієслова.

Приклади включають:

  • Виявляє (наприклад DetectsInvalidUserInput)
  • Кидки (наприклад ThrowsOnNotFound)
  • Буде (наприклад WillCloseTheDatabaseAfterTheTransaction)

тощо.

Інший варіант - використовувати "що" замість "якщо".

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

[ Редагувати ]

Після використання вищезгаданої конвенції про іменування вже трохи довше, я виявив, що префікс If може бути заплутаним при роботі з інтерфейсами. Так буває, що тестовий клас IfSerializer.cs виглядає дуже схожим на інтерфейс ISerializer.cs на " Вкладці відкритих файлів". Це може стати дуже дратівливим при переключенні між тестами, класом, що тестується, та його інтерфейсом. У результаті я б зараз вибрав префікс That over If як.

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

[Test] public void detects_invalid_User_Input()

Я вважаю, що це легше читати.

[ Завершити редагування ]

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


2

У VS + NUnit я зазвичай створюю папки в своєму проекті, щоб групувати функціональні тести разом. Потім я створюю класи тестових кріплень і називаю їх за типом функціональності, яку я тестую. Методи [Тест] названі в рядках Can_add_user_to_domain:

- MyUnitTestProject   
  + FTPServerTests <- Folder
   + UserManagerTests <- Test Fixture Class
     - Can_add_user_to_domain  <- Test methods
     - Can_delete_user_from_domain
     - Can_reset_password

2

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

Мені особисто подобаються найкращі практики, описані в "Посібнику з кишенькового JUnit" ... важко перемогти книгу, написану співавтором JUnit!


3
Не вірите, що це насправді дає відповідь на питання - чи можете ви змінити та відредагувати керівництво JUnit Pocket? Дякую!
Нейт-Вілкінс

0

назва тестового випадку для класу Foo має бути FooTestCase або щось подібне (FooIntegrationTestCase або FooAcceptanceTestCase) - оскільки це тестовий випадок. Див. http://xunitpatterns.com/ щодо деяких стандартних угод про іменування, таких як тест, тестовий кейс, тестовий пристрій, метод тестування тощо.

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