Re[16]: Нафига нужны юнит-тесты?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 08.10.11 17:54
Оценка:
Здравствуйте, gandjustas, Вы писали:

N>>>>Против этого я и не возражал.:) Вопрос в том, насколько они unit.

G>>>А что им мешает быть unit-тестами?
N>>Зависит от глубины переделки. Может оказаться, что неизменна и покрыто неизменившимися тестами только самая внешняя функциональность, которая не может быть сведена к простому "выстрелил вызовом функции — получил ответ — проверил", а требует долгой подготовки среды. Для меня это всё-таки не unit тест. Unit — это когда максимум подготовки среды это расстановка заглушек вместо рабочего кода. Да, это деление не академично, но мне оно полезнее.

G>Вполне правильное деление. Вот только непонятно зачем переделка? Если не писались unit-тесты для кода, то скорее всего не будут написаны, а если будут то от этого будет много затрат без наблюдаемого эффекта.


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

N>>>>>>Что ты называешь вариантами использования?

G>>>>>Это значит все возможные наборы параметров для которых имеются разные пути исполнения.
N>>>>Для меня такое тестирование имеет очень мало смысла, только для отдельных специфических вариантов функций. Полный набор путей исполнения, мягко говоря, бесконечен. Можно было бы только в целях тестирования выделить отдельные логические подблоки типа "продвинуться на шаг алгоритма", выделяя их в функции, но часто это слишком неудобно.
G>>>Вообще-то конечен.
N>>Ну числа типа 2**2**32 всё равно за пределами представления даже в BER:), поэтому я позволил себе "округлить" их до бесконечности.
G>По факту их гораздо меньше.

Уверен? Только на своих примерах?

G>>>Если писать тесты до кода, то он как-то сам адаптируется ;)

N>>Писать тесты до кода означает или гарантированно окончательный дизайн, во что я не верю, или тупую наивность. По крайней мере я других вариантов пока не видел. Если есть где-то место, где это проходит, то там кому-то сильно повезло.
G>Ни разу не означает, потому что есть рефакторинг. Если не рефакторить код, то unit-тесты и не нужны, потому что любое изменение кода будет вызвано или исправлением бага, или изменением требований.

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

N>>Я периодически использовал этот подход — тесты до кода — как стимулятор собственной работы против собственной же лени, то есть проблема была чисто организационная. Но я никогда не предполагал его как средство собственно дизайна. На это годится тестируемость в принципе, а не test-first.

G>Когда напишешь тест то на него уже не получается просто забить, особенно когда gated checkins включено.

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

G> Если ты не пишешь заранее тесты, то рано или поздно у тебя получится забивание на тесты ради скорости написания, а потом тесты сделать, даже с мощными инструментами, очень сложно. Это ты кстати назвал "адаптацией".


Вопрос не в мощных инструментах, вопрос в понимании кода. Нужно вспомнить и войти в контекст. И это не сложно, это просто вопрос времени, которого может на это не быть.

N>>Не так. Оцениваешь функциональность. Пишешь прототип, или даже просто схему на бумаге, что должно делаться и как. Смотришь на него, проводишь фактически design review (хоть в одиночку, но можно и с коллегами), оцениваешь, что и как реализовывать. На этом этапе могут выделяться чёткие подблоки, которые пригодны к тестированию отдельно от остального. Но ещё не под тест, потому что могут интерфейсы и контракты поменяться уже в процессе реализации, когда будет осознан ещё один пласт специфики. Потом всё это приблизительно написано, разделение на составные части, интерфейсы, контракты стабилизировались, теперь нетривиальные внутренние части покрываются базовыми тестами, подтверждающими их работоспособность. В основном это юнит-тесты, с минимальной настройкой среды проверки или вообще без неё, на уровне отдельных функций. Далее рассчитываешь и делаешь функциональные тесты, под базовые юзкейсы компонент, вычищаешь их от багов. В моём случае обычно минимальная единица, обладающая собственным поведением, называется приложением, и делать функциональные тесты для более мелких частей обычно нереально (хотя бывают и такие сущности). На следующем уровне тестируются связки из таких приложений, образующие функциональность части полной системы, например, тракт вокруг конкретной шины от первичных генераторов событий до финальных накопителей; назовём это интеграционными тестами. Только после этого можно говорить о завершении разработки конкретной подсистемы или даже приложения — когда оно показывает корректное прохождение интеграционных тестов. Далее идут общесистемные тесты, это уже делается людьми в QA отделе. Процесс такого развития никак не соответствует продвижению сверху вниз с твёрдой уверенностью в функционале конкретного уровня, а вместо этого можно говорить только о приблизительной чёткости понимания, которая будет доведена до полной уже после пробы на прототипе. Вот-с, где-то так.


G>Многабукафниасилил. Но чтение по диагонали говорит что правильно пишешь, только гораздо шире чем я. Выделенное примерно соответствует тому что я написал, остальное out-of-scope. На этапе прототипирования тесты не нужны. Вообще методика test-first заставляет создавать приложение по слоям сверху вниз. Если заранее не знаешь как оно должно быть, то пишешь прототип без тестов, а потом уже переписываешь (именно переписываешь, нет смысла рефакторить прототип). Это в терминологии называются spike.


Всё это замечательно, но ещё проще и удобнее делать это же без жёсткого test-first :)

N>>Я продолжу эксплуатировать тот же пример — подсчёт codepoints. Ты действительно считаешь, что если функцию такого рода нельзя разделить на части, проверяемые по методу такого whitebox и подменяемые mock'ами, то это "изначально плохо тестируемый код"? Ответь, пожалуйста, конкретно, а не в сторону. Мне таки очень интересно. Пример простой, но полезный.

G>Нет, я считаю только одно: если код для тестирования надо адаптировать, то он "изначально плохо тестируемый".

"Жаль, что мы так и не заслушали начальника транспортного цеха."

G>>>Учитывая что основной язык для тебя — C++,

N>>Ну вот объясни мне — как можно было _так_ читать, чтобы прийти к такому выводу???
G>Сорри, сейчас редко встретишь тех кто пишет на С, а не С++

Так у меня на >99% и не C. :)

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

N>>А если не заниматься безумными гипотезами и учесть, что у меня Erlang и проблем с юнит-тестами в общем-то нет?
N>>Mock'и подставить тривиально, это условия запуска в рантайме. Адекватная модульность обычно или заложена, или легко закладывается.
G>Так эрланг же динамически типизированный, там вообще необходимо тесты писать, п-другому не проверишь.

Местных немерлистов наслушался?;) Проблемы непроверяемости при динамической типизации сильно преувеличены или относятся к отдельным областям, которые для меня диковинка. В случае Erlang даже dialyzer, производящий статический контроль типов, помогает выловить некоторое количество плюх, но основные проблемы не от них.
The God is real, unless declared integer.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.