Unit test Именование лучших практик

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

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

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

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

Ответ 1

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

[UnitOfWork__StateUnderTest__ExpectedBehavior]

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

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

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

[NameOfTheClassUnderTestTests]

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

Ответ 2

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

OrdersShouldBeCreated();
OrdersWithNoProductsShouldFail();

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

Ответ 3

Мне нравится следовать стандарту именования "If, когда вы называете тестовое оборудование после тестируемого устройства (т.е. класса).

Чтобы проиллюстрировать (используя С# и 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" везде становится немного повторяющимся, но, как я уже сказал, это заставляет писателей думать правильно (так может быть хорошо для новичков). Плюс это обычно приводит к читаемому английскому тестовому имени.

Update:

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

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

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

Ответ 4

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

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

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

    test[feature being tested]
    

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

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

    // other methods and properties
}

Испытательным прибором будет:

class PersonTests {

    testAgeCalculationWithNoBirthDate() { ... }

    // or

    testCalculateAge() { ... }
}

Ответ 5

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

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

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

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

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

WhenDivisorIsNonZero_ExpectDivisionResult
WhenDivisorIsZero_ExpectError
WhenInventoryIsBelowOrderQty_ExpectBackOrder
WhenInventoryIsAboveOrderQty_ExpectReducedInventory

Ответ 6

См: http://googletesting.blogspot.com/2007/02/tott-naming-unit-tests-responsibly.html

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

Ответ 7

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

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

Сначала я создам тестовый проект с пространством имен MyApp.Serialization.Tests.

В рамках этого проекта и, конечно, пространства имен я создам класс с именем IfSettings (сохраненный как IfSettings.cs).

Скажем, я тестирую метод SaveStrings(). → Я назову тест CanSaveStrings().

Когда я запустил этот тест, он отобразит следующий заголовок:

MyApp.Serialization.Tests.IfSettings.CanSaveStrings

Я думаю, это очень хорошо говорит мне, что он тестирует.

Конечно, полезно, что на английском языке существительное "Тесты" совпадает с глаголом "тесты".

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

Обычно Testnames должны начинаться с глагола.

Примеры включают:

  • Обнаруживает (например, DetectsInvalidUserInput)
  • Выбрасывает (например, ThrowsOnNotFound)
  • Будет (например, WillCloseTheDatabaseAfterTheTransaction)

и др.

Другой вариант - использовать "this" вместо "if".

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

[изменить]

После более длительного использования соглашения об именовании я обнаружил, что префикс If может сбивать с толку при работе с интерфейсами. Так получилось, что тестовый класс IfSerializer.cs очень похож на интерфейс ISerializer.cs на вкладке "Открыть файлы". Это может стать очень раздражающим при переключении между тестами, тестируемым классом и интерфейсом. В результате я бы теперь выбрал That над If в качестве префикса.

Кроме того, теперь я использую - только для методов в моих тестовых классах, поскольку это не считается лучшей практикой в ​​другом месте - "_" для разделения слов в моих именах методов тестирования, как в:

  • [Test] public void detects_invalid_User_Input() *

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

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

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

Ответ 8

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

Ответ 9

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

Ответ 10

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

Ответ 11

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

Мне лично нравятся лучшие практики, описанные в "JUnit Pocket Guide" ... трудно побить книгу, написанную соавтором, автор JUnit!

Ответ 12

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