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/ для некоторых стандартных соглашений об именах, таких как тест, тестовый пример, тестовое устройство, метод тестирования и т.д.