Pull to refresh

Вдохновение для юнит-тестов

Reading time 4 min
Views 7.4K
Много слов сказано о достоинствах юнит-тестов (TDD, BDD — в данном случае неважно), а также о том, почему люди всё-таки их не используют.

Но я думаю, что одна из главных причин заключается в том, что люди не знают, с чего начать. Вот прочитал я статью про юнит-тесты, понравилось; решил, что надо бы когда-нибудь попробовать. Но что дальше? С чего начать? Как придумывать все эти требования, как называть тест-методы?

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

Об этом и пойдёт речь:

Откуда брать вдохновение



Однажды я пришёл к удивительному открытию: это вдохновение — повсюду, оно окружает нас каждый день. Тут и придумывать ничего не надо. Его можно просто брать и использовать. Это открытие показалось мне настолько важным, что я спешу непременно поделиться им со всеми.

Итак, мой TOP-5 источников вдохновения для написания юнит-тестов.

5. Доклад начальнику


Каждое утро на собрании начальник спрашивает тебя: «Что ты вчера делал?».
— Багу исправлял.
Начальник так просто на слово не верит и продолжает докапываться:
— Какую багу?
— Ну, исправил метод validateReferenceNumber.
— Конкретнее, что ты там исправил?
— Ну, раньше он грохался, если дать ему на входе пустую строку, а теперь он не падает, а возвращает false.


Gotcha!

Видите, практически готовый юнит-тест висит в воздухе у вас перед носом. После собрания садитесь за компьютер и пишете:
public class ReferenceNumberTest {
  @Test
  public void emptyStringIsNotValidReferenceNumber() {
    assertFalse(validateReferenceNumber(""));
  }
}


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

4. Объяснения с коллегами



К вам каждый день приходит какой-нибудь коллега и спрашивает:
— Слушай, я тут твой код дебажу-дебажу, а всё никак не могу понять, как это работает?
Ты ему терпеливо объясняешь:
— Ну как, ну смотри: сюда приходит Б, а отсюда выходит А.
— Всё равно не понимаю, а почему А-то?
— Ну потому, что для всех букв, которые меньше Я, этот метод должен возвращать следующую букву.
— Ааа, вот теперь понятно.


И снова Gotcha!

Вы, сами того не подозревая, только что сформулировали название тест-кейса.
Мысленно послав +1 в карму коллеги, сели и написали:
public class NanoTechnologySecurityTest {
  @Test
  public void shouldReturnNextLetterForAllLettersExceptJa() {
    assertEquals("Б", encodeLetter("А"));
  }
}


3. Разговор с клиентом


В любой прекрасный день клиент может позвонить и сказать:
— Помните, мы обсуждали, что все поля на форме должны валидироваться автоматически, как только поле теряет фокус? Так вот, я передумал. Я показывал бета-версию моей бабушке, и она сказала, что это не понятно, и вообще ajax sucks. Давайте поля будут валидироваться только тогда, когда клиент нажмёт кнопку «Submit».

И опять Gotcha!

Клиент только что сформулировал за нас текст тест-кейса.

Мысленно послав -10 в карму клиента, мы сели и написали… UI тесты, конечно, чуток сложнее, чем обычные юнит-тесты, но это могло бы выглядеть как-то так:

public class TimotiFanClubRegistrationFormTest {
  @Test
  public void shouldValidateFieldsOnFormSubmission() {
    Form form = new Form();
    assertTrue(form.isValid());

    form.submit();
    assertFalse(form.isSubmitted());
    assertFalse(form.isValid());

    form.setName("Baba Njura");
    form.setEmail("Baba.Njura@yandex.ru");
    form.submit();
    assertTrue(form.isSubmitted());
  }
}


2. Баг


Каждый день вы заходите в Jira (а кому совсем повезло — в Pivotal Tracker) и обнаруживаете, что в вашей программе зловредные тестировщики нашли-таки багу. Если вам повезло с тестировщиком, то описание баги звучит примерно так: «Если ввести три раза неправильный пароль, то учётная запись должна заблокироваться, а у меня не блокируется. Я уже раз пятнадцать ввёл.»

Мысленно сказав тестировщику спасибо (хватит с него и спасиба, его карму всё равно не спасёшь), садимся и пишем:
public class LoginPageTest {
  @Test
  public void shouldBlockAccountAfter3UnsuccessfulTries() {
    LoginPage page = new LoginPage();
    page.login("vasjok47", "Toiota");
    page.login("vasjok47", "Tojota");
    page.login("vasjok47", "tayota");
    assertTrue(AccountDAO.getAccount("vasjok47).isBlocked());
  }
}


Есть даже отдельный термин для этого: Bug driven development. Я сам этот подход не жалую, так как юнит-тесты (они же спецификация) всё-таки должны писаться ДО кода (основной принцип TDD), но как источник вдохновения баг-трекер вполне подходит.

1. Commit message (как это по-русски?)


Это мой любимый пункт, на нём я хотел бы остановиться подробнее.

Когда вы меняете код, для этого обычно есть причина. Причина обычно заключается в том, что вы хотите, чтобы этот код что-то делал по-другому (исключаем рефакторинг, улучшение производительности и расставление скобочек по фэншую).

Допустим, был у нас код, который валидировал email. В частности, он проверял, что в конце email должна быть точка и два символа. И даже есть для него юнит-тест, всё как у людей. И тут внезапно выясняется, что после точки может быть и больше букв, например, у некоторых клиентов email заканчивается на ".info". Сказано-сделано, код исправили, и даже в существующий юнит-тест добавили одну строчку:

public class EmailValidatorTest {
  @Test
  public void testValidateEmail() {
    assertTrue(validateEmail("timati@rambler.ru"));
    ...
    assertTrue(validateEmail("tina.turner@music.info")); // 4 letters now allowed!
  }
}


И теперь хотим это дело закоммитить в CVS (а кому повезло, те в SVN, а кто вообще счастливчик, те в GIT).
Для коммита надо написать пояснение (commit message), в котором обычно пишут, а что же в коде изменилось. И вот пишите вы:
svn commit -m "Теперяча мыло и на четыре буквы может заканчиваться."


И вот это самая настоящая Gotcha!

Это то, что нам надо. Не нажимайте пока enter.
Остановились, выделили этот текст мышкой. Открыли класс юнит-теста. Написали Test, вставили скопированный текст и перевели на английский. Можно немножко уточнить или обобщить по вкусу.
public class EmailValidatorTest {
  @Test
  public void validEmailShouldEndWithDotFollowedBySeveralLetters() {
    assertTrue(validateEmail("timati@rambler.ru"));
    ...
    assertTrue(validateEmail("tina.turner@music.info"));
  }
}


Вот теперь можете смело закоммитить и мысленно послать +1 себе в карму. Сегодня мы смогли материализовать некоторые знания из воздуха во что-то более ощутимое. Теперь эти знания никуда не пропадут и будут автоматически проверяться при каждой сборке проекта.

Ну не здоровско ли, а?

Tags:
Hubs:
+83
Comments 50
Comments Comments 50

Articles