Целесообразность unit-тестов

varan

Б̈́̈̽ͮͣ̈Л̩̲̮̻̤̹͓ДͦЖ̯̙̭̥̑͆А͇̠̱͓͇̾ͨД͙͈̰̳͈͛ͅ
Целесообразность unit-тестов

Очень много литературы по поводу того, насколько круты unit-тесты. Однако мне кажется, что их применение нецелесообразно по нескольким причинам.

1) Время.
Убивается совершенно сумасшедшее количество времени. Сначала пишешь класс + тесты к нему. Потом понимаешь, что надо применить рефакторинг, для чего переписываешь код и все его тесты(!). Потом если надо что-то изменить в классе, опять меняешь код и эти чертовы тесты.
Потом в какой-нибудь SQL таблице добавляется поле, и половина тестов слетает, просто потому, что в них была, например, проверка результата хитрой выборки из базы в таком виде:

$waited_assoc_row = array('id'=>'534', 'name' => 'Ваня');
assertEquals($assoc_row, $waited_assoc_row)

а теперь должна быть такая:
$waited_assoc_row = array('id'=>'534', 'name' => 'Ваня', 'newfield' => 'blablabla');
assertEquals($assoc_row, $waited_assoc_row)

К чему это я? Время на эту ботву ГОРАЗДО БОЛЬШЕ времени, затраченного на отлов хитрой неуловимой ошибки. Тем более, что действительно хитрые ошибки unit-тестами не ловятся.


2. Иногда сами тест-функции довольно сложно написать(может
потребоваться создать много объектов), и в них тоже
могут быть баги (которые тоже надо тестировать? :) ). Кроме того, сложные тесты сложнее переделывать при рефакторинге.


Есть ли у кого-нибудь соображения на этот счет? Я это спрашиваю потому, что может я просто чего-то недопонимаю.
 

young

Новичок
Основное правило XP:
1) сначала пишем тесты
2) только потом пишем код.

тесты придают уверенности как автору кода, так и тем новичкам которые в последсвии его модифицируют

И наконец:

Программы, которые не тестировали, НЕ РАБОТАЮТ.
Б. Страуструп
 

varan

Б̈́̈̽ͮͣ̈Л̩̲̮̻̤̹͓ДͦЖ̯̙̭̥̑͆А͇̠̱͓͇̾ͨД͙͈̰̳͈͛ͅ
Автор оригинала: young
Основное правило XP:
1) сначала пишем тесты
2) только потом пишем код.
Это мягко говоря странно. Имеется в виду, конечно, что сначала надо думать об интерфейсе, а потом о реализации, но при таком подходе реально будет такая последовательность событий
1) сначала пишем тесты
2) только потом пишем код.
3) потом понимаем, что так код не написать
4) переписываем тесты
5) переписываем код
:)

тесты придают уверенности как автору кода, так и тем новичкам которые в последсвии его модифицируют
С этим согласен, но цена этой уверенности - двух-трех кратное увеличение времени разработки. Да и все равно 100% уверенности не будет, т.к. все необходимые тесты предусмотреть невозможно.

И наконец:

Программы, которые не тестировали, НЕ РАБОТАЮТ.
Б. Страуструп
Я не говорю, что программы вообще не надо тестировать. Я говорю, что программы не надо тестировать автоматизированными unti-тестами
 

GD

Guest
Автор оригинала: varan
С этим согласен, но цена этой уверенности - двух-трех кратное увеличение времени разработки. Да и все равно 100% уверенности не будет, т.к. все необходимые тесты предусмотреть невозможно.
IMHO, тесты пишутся (дописываются) по мере надобности, думается с множителем ты подзагнул...
каким еще образом можно прибавить уверенности окромя вердикта "Все работает так как надо"?

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

вот именно в таком случае удобнее взять тесты, которые этот год писали, запустить и через 1...2 минуты понять что именно ты успел поломать за последнюю правку...

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

young

Новичок
Где-то я видел сравнения по стоимости

если время разработки увеличится в 1,5 раза, но при этом количество багов будет в два раза меньше, то такой проект будет коммерчески выгодней, чем исходный

на локализацию бага в крупной системе после полугода эксплуатации может уходить месяц времени
 

Crazy

Developer
Автор оригинала: varan
3) потом понимаем, что так код не написать
1. Анализируем задачу.
2. Формируем интерфейс. На этом этапе мы уже понимаем, что делаем, какие данные нужны на входе и что нужно вернуть.
3. Пишем тест. Убеждаемся при этом, что правильно сформулировали интерфейс.
4. Реализуем интерфейс.

Ситуация "ПОТОМ понимаем, что код так не написать" возможна только в случае жестокого ламерения на этапах 1 и 2. Возможно -- 3. В моей практике было ровно 0 случаев, когда при использовании такой методики разработки вдруг оказывалось, что интерфейс не реализуем.
 

su1d

Старожил PHPClubа
si, а кто говорил про ХР?
это была уже догадка young'а.


varan, "лучше день потерять, зато потом за 5 минут долететь" (с)
"потерянное" на написании юнит-тестов время с лихвой окупится при поддержке проекта.

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

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

кстати, не зря здесь заговорили об ХР (eXtreme Programming), т.к. одним из основных его постулатов является: "написать юнит-тест -- ДО создания тестируемого модуля". именно это и имел в виду young.

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

confguru

ExAdmin
Команда форума
Лично мне XP не нравится но некоторые полезные фичи - грех не использовать....
 

trigger

Guest
varan
Сразу оговорюсь, что еще не использовал юнит-тесты. Только читал теорию.

" Кроме того, сложные тесты сложнее переделывать при рефакторинге."
AFAIK, юнит-тесты делаются для того, чтобы удобнее было делать рефакторинг. Увереннее. И уж конечно далеко не всегда надо переписывать тесты для рефакторинга.

"Потом в какой-нибудь SQL таблице добавляется поле, и половина тестов слетает,"
Может надо делать тесты менее зависящими от изменений? Более абстрактными или типа того... А на добавление 'newfield' писать еще один тест.
 

varan

Б̈́̈̽ͮͣ̈Л̩̲̮̻̤̹͓ДͦЖ̯̙̭̥̑͆А͇̠̱͓͇̾ͨД͙͈̰̳͈͛ͅ
Автор оригинала: trigger
varan
Сразу оговорюсь, что еще не использовал юнит-тесты. Только читал теорию.

" Кроме того, сложные тесты сложнее переделывать при рефакторинге."
AFAIK, юнит-тесты делаются для того, чтобы удобнее было делать рефакторинг. Увереннее. И уж конечно далеко не всегда надо переписывать тесты для рефакторинга.
Если я делаю extract class, то мне по как минимум надо перенести тесты к другому классу и переписать все new. Это просто как пример.

"Потом в какой-нибудь SQL таблице добавляется поле, и половина тестов слетает,"
Может надо делать тесты менее зависящими от изменений? Более абстрактными или типа того...
Да я сам догадался, представь себе :) Но от таких ситуаций никто не застрахован, т.к. все предусмотреть невозможно.
Реальность показывает, что программа постоянно видоизменяется, особенно если активно применять рефакторинг.

Другими словами, я хочу сказать, что, хотя и появляется уверенность при написании программы, зато может появиться неуверенность: правильно ли я пишу тесты? Всё ли я протестировал? Не слишком ли подробно я это тестирую?

И главное, что очень сложно психологически, постоянно приходит в голову мысль, а не зря ли я трачу столько времени?
Я для того и начал эту тему, чтобы убедиться до конца, надо или не надо писать тесты, и больше не психовать :).

На самом деле, я еще раз попробую, когда появится какой-нибудь серьезный проект.
 

trigger

Guest
varan
"На самом деле, я еще раз попробую, когда появится какой-нибудь серьезный проект."
Мое мнение вообще об ХР -- это вторая часть твоего предложения. А в общем я с тобой согласен -- для небольших проектов они не нужны.
 

Serg

Guest
Несколько мыслей на сию тему...

1. Unit tests никак не завязаны на XP, это XP методология завязана на unit tests. Соответственно сразу снимается вопрос к обязаловке парадигмы test first. Кстати, есть много методологий использующих unit tests, просто XP нынче особо популярна (для примера see SCRUM).

2. Очень правильно было сказано о проверки разумности интерфейсов при построении юнит тестов, только одно "но" - вообще-то интерфейсы проверяются на этапе проектирования модели, что разумно делать используя UML системы проектирования. Юнит тесты не проверка логики модели! Это скорее проверка ожидаемой реакции модуля! Опять же, многие системы проектирования позволяют сразу же генерить скелеты юнит тестов. Впрочем, это не в разрез с XP, там то же до написания кода этап проектирования присутствует (User stories, CRC карточки и т.п.).

P.S. Да, кстати - функциональные тесты! Это в XP как раз для тестировани соответствия модели user story.

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

4. Ну и в заключение. "Hello world", это все же абстракция. Любая реально живущая система (хоть тот же движок сайта) имеет вполне достаточный объем для применения юнит тестов, исключение одно - если Вы продали систему и забыли.
 

Crazy

Developer
Автор оригинала: Serg
1. Unit tests никак не завязаны на XP, это XP методология завязана на unit tests. Соответственно сразу снимается вопрос к обязаловке парадигмы test first.
Практика показывает, что в отрыве от "test before code" во время запарки первым делом забивают на тестирование. Проверено кучей проектов.

вообще-то интерфейсы проверяются на этапе проектирования модели, что разумно делать используя UML системы проектирования.
А нельзя ли подробнее о методике ПРОВЕРКИ интерфейсов на этапе проектирования? Особливо -- о том, как в этом помогает UML.
 

Serg

Guest
Автор оригинала: Crazy
... первым делом забивают на тестирование.
Это вопрос дисциплины и только. Когда реализуешь некий класс по модели, а потом пишешь тест, иначе его все равно не опробовать, сие вполне безобидно. ИМХО, если на этапе написания теста проектируешь интерфейс, это не очень вяжется с OOAD. В XP много хорошего, но это же не отменяет необходимость сначала подумать ;)

Автор оригинала: Crazy
.. о методике ПРОВЕРКИ интерфейсов на этапе проектирования?
ПРОВЕРКА применима только к модели в целом!
1. Сегодняшние UML тулзы ни есть панацея да еще с полным автоконтролем. Что, кстати, есть большое свинство со стороны разработчиков - в стандарте UML существует понятие "правил непротиворечивости", по которым вполне возможен авто-анализ. Да только что Rational, что прочие спокойно наплевали на эту часть стандарта, понимаю, сложно релизовать, лучше прилечь на лаврах ;-)) Сорбственно, рекомендую поискать инфу на этот счет. Это как раз и будет первый метод. Пересказать не берусь, испорченый телефон выйдет.

2. Все же есть некоторые "автоматы" типа аудита в Together. Смысл - есть набор метрик, модель оценивается на слишком "толстые" или "тонкие" сущности избыточное количество связей и т.п. Правда, сие примитивно.

3. Ну и есть некоторые прихваты, помогающие жить. Если кратенько - все велосипеды уже придуманы до нас, остается выучить правильные и не правильные ходы (см. Тейт Б. "Горький вкус Java" в основном применимо для любого языка). А UML просто помогает визуально оценить где в модели квадратные шестеренки. Тема на хорошую книгу, что не по силам, конкретика для примера:

Sequence-куча цепочек мелких операций, не понятный срок жизни объектов-прямой сигнал пора вводить "фасад".

Сущность похожа на паука в Collaboration - папа затесался на уровень дочек.

Нет extend points в UseCase,интерфейсы между пакетами уже не выйдут с приставкой "интер" ;-))


И т.п.
 

csa

Guest
кто может привести практический пример unit-теста для кода, работающего с базой?
каков подход к написанию таких тестов? ведь нужна тестовая база (в общем случае - пустая), какое-то тестовое наполнение
я пока не очень представляю себе процесс
 

AlexVN

Новичок
Практический пример:
Есть несколько баз (MySQL, PgSQL, etc) на ~ 50 таблиц с тестовыми даными.
Есть 600 страниц с тестами. Все это каждые 2 дня прогоняется и результаты скриптов сравниваются с теми, которые должны быть.
 

Krisha

pain in the neck
csa
Идея в чем. Вот тебе нужно создать ну, пусть будет некий класс Company, у которого ты заранее знаешь, будут методы
add() и delete(). И ты уже знаешь как эти методы должны работать. Ты пишешь нечтно вроде программы-робота, которая будет при вызове последовательно:

- создаст объект Company() с какими-то параметрами
- вызовет метод add()
- потом вызовет метод delete()
- выведет тебе результат, прошло ли всё хорошо или нет

Это программа и будет юнит-тестом.
 

csa

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

varan

Б̈́̈̽ͮͣ̈Л̩̲̮̻̤̹͓ДͦЖ̯̙̭̥̑͆А͇̠̱͓͇̾ͨД͙͈̰̳͈͛ͅ
Правильно. Меня это тоже беспокоит.
Я уверен, что в NASA при разработке марсохода тестируется всё и вся, и имитируется окружение, но у них и денег для этого до фига и ресурсов.
 
Сверху