Стандарты кодирования модульных тестов


22

Обычно, когда мы говорим о стандартах кодирования, мы ссылаемся на код самой программы, но как насчет модульных тестов? Существуют ли определенные рекомендации по стандартам кодирования, которые являются уникальными для модульных тестов? Кто они такие?

Ответы:


12

Вдобавок ко всему, я могу думать о трех различиях в стиле кодирования для тестового кода.

В именовании методов испытаний я следую схеме shouldDoSomethingWhenSomeConditionHolds.

Внутри теста принято следовать следующему интервалу:

@Test
shouldReturnAccountBalenceWhenGetBalenceIsCalled() {
    // Some lines 
    // of setup code
    // go here.

    // The action being tested happens after a blank line.

    // An assertion follows another blank line.
}

Некоторые настаивают только на одном утверждении на тест, но это далеко не универсально.

СУХОЙ (не повторяйся сам) менее важен в тестовом коде, чем в рабочем коде. Хотя некоторый повторяющийся код должен быть помещен в метод setUp или класс testUtils, стремление к нулевому повторению в тестовом коде приведет к тесно связанным и негибким тестам, что препятствует рефакторингу.


Конечно, существует множество шаблонов, поэтому вы также должны дать ответ.
Эрик Уилсон,

10
Это шаблон Arrange, Act, Assert .
StuperUser

СУХОЙ по-прежнему важно. Если вам нужно сделать одни и те же утверждения в нескольких тестах, создайте общую функцию и вызовите ее во всех тестах.
MiFreidgeim SO-перестань быть злым

@MichaelFreidgeim Возможно, мы просто говорим о градусах, но у меня значительно выше допуск повторения в тестовом коде. У меня был опыт создания наборов тестов с очень небольшим повторением, и я обнаружил, что тесты стало сложно модифицировать и понимать при изменении требований. Затем я перестал беспокоиться о DRY в тестах, и мои тестовые наборы стали проще в использовании. <
Эрик Уилсон

16

Рой Ошеров рекомендует следующую схему именования ваших тестов:

NameOfMethodUnderTest_StateUnderTest_ExpectedBehavior() 

См. Http://weblogs.asp.net/rosherove/archive/2005/04/03/TestNamingStandards.aspx


Я согласен с Роем. Это улучшает читаемость, хотя ReSharper постоянно говорит мне, что я должен удалить их NameOfMethodUnderTestStateUnderTestExpectedBehavior();)
Оскар Медерос

Как заставить это работать, когда метод перегружен, чтобы могло быть несколько методов с одинаковым именем?
Нарендра Патхай

6

Главное помнить, что юнит-тесты - это, по сути, мини-спецификации. Это означает, что акцент всегда должен делаться на удобочитаемости.

Во-первых, это означает, что имена должны четко отражать то, что проверяется и что утверждается.

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

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

Я просто завершу с несколькими рекомендациями книги:

Тестовые шаблоны xUnit: рефакторинг тестового кода: отличная книга, некоторые говорят, что она немного сухая, но я так не думаю. Подробно рассказывается о множестве различных способов организации тестов и о том, как их поддерживать. Уместно, если вы используете что-то вроде NUnit и т. Д.

Искусство модульного тестирования: с примерами в .Net : Лучшая книга о том, как писать и поддерживать тесты. Несмотря на то, что я действительно новичок, я считаю, что разделы насмешек уже устарели, так как синтаксис AAA теперь довольно стандартный, а не просто другой способ сделать это.

Растущее объектно-ориентированное программное обеспечение, ориентированное на тесты : эта книга просто потрясающая! Безусловно, лучшая книга по модульному тестированию и единственная продвинутая, которая ставит модульное тестирование в качестве первоклассного гражданина в процессе проектирования. Читал это, когда это была публичная бета-версия и с тех пор рекомендую. Превосходный, реально работающий пример, используемый на протяжении всей книги. Рекомендую сначала прочитать книгу Роя.


ИМХО нормально, чтобы модульные тесты содержали логику: вполне разумно тестировать высокооптимизированную и эффективную версию алгоритма, используя наивный алгоритм, который делает то же самое для определения правильного поведения. Например, представьте себе тестирование хеш-таблицы путем создания ассоциативного массива на основе линейного поиска.
дсимча

2
Да, но это относится за пределами теста в сборщиках тестовых данных (которые сами должны быть модульными, если логика внутри них не тривиальна). Исключением из этого могут быть сторонние библиотеки, которые, как правило, «доверяют», чтобы быть корректными и могут использоваться без тестов.
FinnNk

3

Не помещайте логику в свои юнит-тесты. Например, предположим, что вы тестируете метод add, у вас может быть что-то вроде этого:

void MyTest_SaysHello()
{
   string name = "Bob";
   string expected = string.Format("Hello, {0}", name);
   IMyObjectType myObject = new MyObjectType();
   string actual = myObject.SayHello(name);
   Assert.AreEqual(expected, actual);
}

В этом конкретном случае вы, скорее всего, повторяете ту же логику, что и в тесте, поэтому вы в основном тестируете «1 + 1 == 1 + 1», а не «1 + 1 == 2», то есть «настоящий» тест. Итак, что вы действительно хотите, чтобы ваш тестовый код был похож на это:

void MyTest_SaysHello()
{
   string expected = "Hello, Bob";
   IMyObjectType myObject = new MyObjectType();
   string actual = myObject.SayHello("Bob");
   Assert.AreEqual(expected, actual);
}

2
Небольшое исправление: я думаю, что вы имели в виду «строка ожидается = строка. Формат (« Привет, Боб »)» должен быть «строка ожидается =« Привет, Боб »».
Майк Розенблюм

@MikeRosenblum вы, очевидно, правы, и кто-то пытался это исправить, но два рецензента отклонили это редактирование
Конрад Моравский

@ Конрад: это странно. Это форум по программированию, верно?
Майк Розенблюм

Я еще раз отредактировал ответ в соответствии с предложением Майка Розенблюма.
bdsl

0

Длинные, описательные имена методов. Помните, что методы тестирования никогда не вызываются из кода (они вызываются исполнителем модульных тестов, который обнаруживает и вызывает их посредством отражения), поэтому можно сходить с ума и иметь имена методов длиной 50-80 символов. Конкретное соглашение об именах (верблюд, нижнее подчеркивание, «должен», «должен», «когда», «дано» и т. Д.) Не очень важно, если имя отвечает на три вопроса:

  • что тестируется?
  • какие условия?
  • Каков ожидаемый результат?

Методы испытаний должны быть короткими .

Методы испытаний должны иметь простую линейную структуру . Нет, если или цикл конструкций.

Методы испытаний должны следовать шаблону "организовать-действовать-утверждать" .

Каждый тест должен проверять одну вещь . Обычно это означает одно утверждение за тест. Тест , как { Do A; Assert B; Assert C; }должны быть переработаны на два: { Do A; Assert B; }и{ Do A; Assert C; }

Избегайте случайных данных или таких вещей, как «DateTime.Now»

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

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


-1

Что-то похожее на то, что Фармбой уже упоминал, формат имени моего метода

 <MethodName>Should<actionPerformed>When<Condition>

например

 GetBalanceShouldReturnAccountBalance() {
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.