Хрупкие тесты

Lightning

Трудоголик
Чувствительные тесты

Попадаю в ловушку с TDD. Попытаюсь абстрактно сформулировать суть проблем:

Допустим есть класс B, для него есть тест. Есть так же n-ое количество классов A1,A2,...,An , каждый из которых использует класс B (создает экземпляр класса B или наследуется от класса B, неважно, главное, что зависит от B). Для каждого класса A1,A2,...,An естественно существуют тесты. Допустим необходимо внести изменение в систему. Для этого нужно изменить класс B и это изменит результаты работы классов A1,A2,...,An. Получается, что в итоге нужно изменить один класс рабочего кода и n+1 тестов ! Получается - тесты слишком чувствительные.
Почему так получается. При тестировании каждого класса из A1,A2,...,An, работает и код класса B. Т.е. неявно происходит повторное тестирование класса B. Т.е. получается в тестах существует неявное дублирование.

Вопрос:
Как избавиться от подобного рода чувствительности тестов?

Скорее всего, будет дан ответ: снизить зависимость между классами A1,A2,...,An и B.
Но если это не возможно, что тогда?
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
тогда расписать нам логику, описать зависимости, а мы подскажем, как эту зависимость снизить
 

Lightning

Трудоголик
тогда расписать нам логику, описать зависимости, а мы подскажем, как эту зависимость снизить
Любую зависимость можно снизить? А если классы A1,A2,...,An потомки класса B?
 

whirlwind

TDD infected, paranoid
Ты сам подумай, если у тебя тесты реагируют на изменения - это же круто! Если бы ты моками все заткнул, было бы сложнее.

-~{}~ 11.05.09 02:35:

PS. ответ на вопрос - агрегация (декомпозиция). иначе никак.
 

atv

Новичок
создает экземпляр класса B или наследуется от класса B, неважно, главное, что зависит от B
Как раз очень важно. В случае использования экземляра класса, можно использовать моки.

Естественно, если меняется интерфейс класса В, то, есть тесты, или нет, придётся переписывать много кода, в частности рабочего, и переписывание тестов не самая большая работа. Но, интерфейсы можно улучшать, сохраняя обратную совместимость, так что проблема не настолько острая.

В случае наследования, наверно нет смысла тестировать в классах А функционал, протестированный в классе В.

Вообще, в моей небольшой практике ТДД, не часто приходилось переделывать интерфейс класса, в основном дописывать, соответственно, дописывать и тесты. Ну а тут всё логично.
 

Lightning

Трудоголик
Ты сам подумай, если у тебя тесты реагируют на изменения - это же круто!
Может это и круто, но при изменении одного класса, нужно менять много тестов. Это сводит на нет весь смысл старания избавиться от дублирования в коде.

PS. ответ на вопрос - агрегация (декомпозиция). иначе никак.
Надо подумать. Там вроде однозначно отношение "является". Надо подумать...

Кстати, вот еще вопрос. В результате рефакторинга появляются абстрактные классы, стоит ли их тестировать?
 

zerkms

TDD infected
Команда форума
Lightning
Может это и круто, но при изменении одного класса, нужно менять много тестов. Это сводит на нет весь смысл старания избавиться от дублирования в коде.
хех... а ты как хотел? тест у тебя - проверка ожидаемости реакции на набор входных аргументов. если ты нахерачишь моков, и тем самым зависимые классы обезопасишь от хрупкости в тестах - ты получишь хрупкий боевой код. т.е. тесты у тебя будут зелёные, а код сломается. и в итоге ты пойдёшь и будешь менять моки. более того - моки тебе менять будет ой как непросто - ведь полоски то у тебя зелёные.
 

Lightning

Трудоголик
zerkms
Да я еще не говорю ничего про моки.

-~{}~ 11.05.09 16:06:

У меня тут возникла идея извращенная немного. Вот я меняю класс B и тест для него. У меня появляется много красных тестов. Но я то знаю, что код правильный. Может написать скрипт, который сгенерит зеленые тесты для всех этих классов?
 

cDLEON

Онанист РНРСlub
Напиши тест на весь проект:
PHP:
$testCase->assertTrue(true)
и радуйся, что у тебя тесты зелёные всегда.

-~{}~ 11.05.09 19:03:

ЗЫ. Если ты знаешь, что у тебя дальше всё правильно, то не используй ТДД, гений.
 

Lightning

Трудоголик
ЗЫ. Если ты знаешь, что у тебя дальше всё правильно, то не используй ТДД, гений.
Невнимательно читал?

-~{}~ 11.05.09 19:20:

Я меняю код класса B, а код классов A1,A2...An остается правильный
 

cDLEON

Онанист РНРСlub
Если ты меняешь код класса б, а тесты в классах А1,А2 ломаются, значит ты в классах А1,А2 ЯВНО тестируешь класс Б, вместо того, что бы тестировать классы А1,А2.
 

Lightning

Трудоголик
cDLEON
Не ЯВНО. Просто результаты работы классов A1,A2,An зависят от класса B, т.к. A1,A2,An используют класс B.

Наверное мне стоит попытаться привести примеры кода...
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
>Наверное мне стоит попытаться привести примеры кода
ура! даже суток еще не прошло, а Lightning смог понять смысл 1го комментария
растем :)
 

Alexandre

PHPПенсионер
Любую зависимость можно снизить? А если классы A1,A2,...,An потомки класса B
а так ли это необходимо? может есть другие способы?
классики ООП рекомендуют использовать наследование если есть отношение типа "является частью ..." Во всех других случаях использовать декомпозицию. Недостаток наследования именно в костности зависимости от базового класса. Встречал одного юнного гения, так он сделал базовый класс Log, от которого наследовались все классы его МегаЦМС...
 

zerkms

TDD infected
Команда форума
классики ООП рекомендуют использовать наследование если есть отношение типа "является частью ..." Во всех других случаях использовать декомпозицию.
и что? из этого следует, что поведение класса-предка в процессе развития проекта не может измениться?
 

Alexandre

PHPПенсионер
нет, просто если мы имеем другой тип отношения, то выстраивается не правильная архитектура и система становится жесткой. Следствием может стать что маленькие изменения в требованиях могут привести к большим переделкам в коде.
Как пример, Ты же не делаешь потомки функциональных модулей от родительского класса DB? А я не раз встречал это в кодах... как указал выше - даже встречал базовый класс для всех модулей ЦМС - был класс Log
А теперь докажи мне - что это правильно!!!
 
Сверху