Зазвичай, коли ми говоримо про стандарти кодування, ми посилаємося на код самої програми, але як бути з одиничними тестами? Чи існують певні рекомендації щодо стандартів кодування, які є унікальними для одиничних тестів? Хто вони?
Зазвичай, коли ми говоримо про стандарти кодування, ми посилаємося на код самої програми, але як бути з одиничними тестами? Чи існують певні рекомендації щодо стандартів кодування, які є унікальними для одиничних тестів? Хто вони?
Відповіді:
Я маю на увазі три відмінності стилю кодування для тестового коду.
При іменуванні методів тестування я слідую за схемою 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.
}
Деякі наполягають лише на одному твердженні за тест, але це далеко не універсальне.
DRY (не повторюй себе) менше враховує тестовий код, ніж виробничий код. Хоча деякий повторний код повинен бути розміщений у методі setUp або класі testUtils, прагнення до нульового повторення тестового коду призведе до жорстко пов'язаних і негнучких тестів, що відлякує рефакторинг.
Рой Ошерово рекомендує наступний зразок для назви своїх тестів:
NameOfMethodUnderTest_StateUnderTest_ExpectedBehavior()
Дивіться http://weblogs.asp.net/rosherove/archive/2005/04/03/TestNamingStandards.aspx
NameOfMethodUnderTestStateUnderTestExpectedBehavior()
;)
Головне пам’ятати, що одиничні тести по суті є міні-специфікаціями. Це означає, що акцент завжди повинен бути зроблений на читанні.
По-перше, це означає, що імена повинні чітко повідомляти про тестування і те, що стверджується.
По-друге, що іноді забувається, що як специфікації вони повинні робити саме це - конкретизуючи поведінку. Тобто, одиничні тести не повинні містити логіки - або, можливо, вони потрапляють у пастку повторення функціональності програми, а не тестування її.
Іноді тести включатимуть об'єкти, які складно налаштувати, ви повинні прагнути, щоб ця логіка налаштування була окремою від ваших тестів, використовуючи щось на зразок матері об'єкта або конструктора тестових даних .
Я лише завершу кілька книжкових рекомендацій:
Шаблони тестування xUnit: Тестовий код рефакторингу: Відмінна книга, деякі кажуть, що вона трохи суха, але я не думаю. Докладно описується багато різних способів організації тестів та способів їх збереження. Доречно, якщо ви використовуєте щось на зразок NUnit тощо.
Мистецтво одиничного тестування: з прикладами в. Net : Найкраща книга про солодкуватість написання та підтримки тестів. Незважаючи на те, що він є справді новим, я вважаю, що глузуючі розділи трохи датовані вже як синтаксис AAA - тепер досить стандартний, а не просто інший спосіб зробити це.
Вирощування об’єктно-орієнтованого програмного забезпечення, керуючись тестами : Ця книга просто дивовижна! На сьогоднішній день найкраща книга тестування одиниць і єдина вдосконалена книга, яка ставить тестування одиниць як першокласного громадянина в процесі проектування. Читав це, коли це була загальнодоступна бета-версія, і з тих пір рекомендую. Прекрасний реальний приклад, що працював у реальному світі, який використовується у всій книзі. Я б рекомендував спочатку прочитати книгу Роя.
Не вкладайте логіку у ваші одиничні тести. Наприклад, скажімо, ви тестуєте метод додавання, ви можете мати щось подібне:
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);
}
Довгі описові назви методів. Пам'ятайте, що тестові методи ніколи не викликаються з коду (їх викликає блок-тестувальник, який виявляє та викликає їх за допомогою відображення), тому нормально сходити з розуму та мати назви методів довжиною 50-80 символів. Конкретна умова іменування (верблюд, випадок підкреслення, "повинен", "повинен", "коли", "дано" і т. Д.) Насправді не важлива, поки назва відповідає на три питання:
Методи випробувань повинні бути короткими .
Методи випробувань повинні мати просту лінійну структуру . Ні, якщо або циклічні конструкції.
Методи випробувань повинні відповідати схемі "домовитись-затвердити" .
Кожен тест повинен перевірити одне . Зазвичай це означає одне твердження за тест. Тест на кшталт { Do A; Assert B; Assert C; }
повинен бути перероблений на два: { Do A; Assert B; }
і{ Do A; Assert C; }
Уникайте випадкових даних або таких речей, як "DateTime.Now"
Переконайтесь, що після закінчення випробування всі елементи кріплення для випробувань повертаються до їх початкового стану (наприклад, використовуючи тертя )
Навіть якщо ви безжально видаляєте дублювання у своєму виробничому коді, дублювання коду в тестових приладдях викликає набагато меншу стурбованість.
Дещо подібний до того, що Farmboy вже згадував, Формат назви мого методу
<MethodName>Should<actionPerformed>When<Condition>
напр
GetBalanceShouldReturnAccountBalance() {