Рекомендации по именованию модульных тестов

Каковы лучшие практики для именования классов юнит-тестов и методов тестирования?

Это обсуждалось на SO ранее, в Каковы некоторые популярные соглашения об именах для модульных тестов?

Я не знаю, является ли это очень хорошим подходом, но в настоящее время в моих тестовых проектах у меня есть взаимно-однозначные сопоставления между каждым рабочим классом и классом тестирования, например Product а также ProductTest,

В моих тестовых классах у меня есть методы с именами методов, которые я тестирую, подчеркивание, а затем ситуация и то, что я ожидаю, например Save_ShouldThrowExceptionWithNullName(),

12 ответов

Решение

Мне нравится стратегия именования Роя Ошерова, это следующее:

[UnitOfWork_StateUnderTest_ExpectedBehavior]

Он содержит всю необходимую информацию о названии метода и структурированно.

Единица работы может быть как один метод, класс или как несколько классов. Он должен представлять все вещи, которые должны быть проверены в этом тестовом примере и находятся под контролем.

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

[NameOfTheClassUnderTestTests]

Ранее я использовал Fixture в качестве суффикса вместо тестов, но я думаю, что последний является более распространенным, тогда я изменил стратегию именования.

Мне нравится следовать стандарту именования "Должен" для тестов, при этом присваивая имя тестовому устройству после тестируемого модуля (то есть класса).

Чтобы проиллюстрировать (используя 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));
  }
}

Почему "должен"?

Я считаю, что это вынуждает авторов тестов называть тест с предложением в виде строки "Должен [быть в каком-то состоянии] [после / до / когда] [действие имеет место]"

Да, написание "следует" везде становится немного повторяющимся, но, как я уже сказал, это заставляет писателей мыслить правильно (что может быть полезно для новичков). Плюс это обычно приводит к читаемому английскому имени теста.

Обновление:

Я заметил, что Джимми Богард также является поклонником "следует" и даже имеет библиотеку модульных тестов " Должен".

Обновление (4 года спустя...)

Для тех, кто заинтересован, мой подход к тестированию имен развивался годами. Одна из проблем с шаблоном " Должен быть", который я описал выше, так как не сразу понятно, какой метод тестируется. Я думаю, что для ООП имеет смысл начинать имя теста с тестируемого метода. Для хорошо разработанного класса это должно привести к читаемым именам тестовых методов. Я сейчас использую формат, похожий на <method>_Should<expected>_When<condition>, Очевидно, что в зависимости от контекста вы можете заменить глаголы "Должен / Когда" на что-то более подходящее. Пример:Deposit_ShouldIncreaseBalance_WhenGivenPositiveValue()

Мне нравится этот стиль именования:

OrdersShouldBeCreated();
OrdersWithNoProductsShouldFail();

и так далее. Это действительно ясно для не тестера, в чем проблема.

Кент Бек предлагает:

  • Один тестовый прибор на единицу (класс вашей программы). Испытательные приспособления сами являются классами. Имя испытательного прибора должно быть:

    [name of your 'unit']Tests
    
  • Тестовые случаи (методы тестового крепления) имеют такие имена, как:

    test[feature being tested]
    

Например, имея следующий класс:

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

    // other methods and properties
}

Тестовое приспособление будет:

class PersonTests {

    testAgeCalculationWithNoBirthDate() { ... }

    // or

    testCalculateAge() { ... }
}

Имена классов. Что касается имен тестовых приборов, я обнаружил, что "Тест" довольно распространен в вездесущем языке многих доменов. Например, в инженерной области: StressTestи в области косметики: SkinTest, Извините, что не согласен с Кентом, но использую "Test" в моих тестовых приспособлениях (StressTestTest?) сбивает с толку.

"Единица" также часто используется в доменах. Например MeasurementUnit, Класс называется MeasurementUnitTest тест "Измерение" или "MeasurementUnit"?

Поэтому мне нравится использовать префикс "Qa" для всех моих тестовых классов. Например QaSkinTest а также QaMeasurementUnit, Его никогда не путают с объектами домена, и использование префикса, а не суффикса означает, что все тестовые приборы живут вместе визуально (полезно, если в вашем тестовом проекте есть подделки или другие вспомогательные классы)

Пространства имен. Я работаю в C# и держу свои тестовые классы в том же пространстве имен, что и класс, который они тестируют. Это удобнее, чем иметь отдельные тестовые пространства имен. Конечно, тестовые классы находятся в другом проекте.

Имена методов испытаний. Мне нравится называть мои методы WhenXXX_ExpectYYY. Это делает предварительное условие ясным и помогает с автоматизированной документацией (в виде TestDox). Это похоже на совет в блоге по тестированию Google, но с большим разделением предварительных условий и ожиданий. Например:

WhenDivisorIsNonZero_ExpectDivisionResult
WhenDivisorIsZero_ExpectError
WhenInventoryIsBelowOrderQty_ExpectBackOrder
WhenInventoryIsAboveOrderQty_ExpectReducedInventory

Я использую понятие " дано, когда". Взгляните на эту короткую статью http://cakebaker.42dh.com/2009/05/28/given-when-then/. Статья описывает эту концепцию в терминах BDD, но вы можете использовать ее и в TDD без каких-либо изменений.

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

Допустим, я тестирую класс 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] публичный void detects_invalid_User_Input() *

Я считаю, что это легче читать.

[ Конец редактирования ]

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

Смотрите: http://googletesting.blogspot.com/2007/02/tott-naming-unit-tests-responsibly.html

Что касается имен методов тестирования, я лично нахожу использование подробных и самодокументированных имен очень полезным (наряду с комментариями Javadoc, которые дополнительно объясняют, что делает тест).

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

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

Мне лично нравятся лучшие практики, описанные в "Карманном руководстве JUnit"... трудно превзойти книгу, написанную соавтором JUnit!

В VS + NUnit я обычно создаю папки в своем проекте для группировки функциональных тестов вместе. Затем я создаю классы тестовых модулей и называю их по типу функциональности, которую я тестирую. Методы [Test] названы в соответствии с 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

Имя тестового примера для класса Foo должно быть FooTestCase или что-то подобное (FooIntegrationTestCase или FooAcceptanceTestCase) - поскольку это тестовый случай. см. http://xunitpatterns.com/ для некоторых стандартных соглашений об именах, таких как test, test case, test fixture, test test и т. д.

Другие вопросы по тегам