Мне поручено получить устаревшее приложение под модульным тестом. Сначала немного информации о приложении: это 600-килобайтная кодовая база Java RCP с этими серьезными проблемами.
- массовое дублирование кода
- нет инкапсуляции, большая часть личных данных доступна извне, некоторые бизнес-данные также являются одиночными, поэтому их можно изменять не только извне, но и повсюду.
- нет абстракций (например, нет бизнес-модели, бизнес-данные хранятся в Object [] и double [] []), поэтому нет OO.
Есть хороший набор регрессионных тестов, и эффективная команда QA тестирует и находит ошибки. Я знаю методы, как проверить это из классических книг, например, Майкла Фезерса, но это слишком медленно. Поскольку существует работающая система регрессионных тестов, я не боюсь агрессивно реорганизовать систему, чтобы позволить писать модульные тесты.
Как мне начать атаковать проблему, чтобы быстро получить некоторое освещение , чтобы я мог показать прогресс менеджменту (и фактически начать зарабатывать на страховке из тестов JUnit)? Я не хочу использовать инструменты для создания наборов регрессионных тестов, например, AgitarOne, потому что эти тесты не проверяют, если что-то правильно.
источник
Ответы:
Я полагаю, что есть две основные оси, по которым может быть размещен код, когда дело доходит до введения модульных тестов: A) насколько тестируемый код? и B) насколько он стабилен (т. е. насколько срочно требуются тесты)? Глядя только на крайности, это дает 4 категории:
Категория 1 является очевидным местом для начала, где вы можете получить большую выгоду при относительно небольшой работе. Категория 2 позволяет вам быстро улучшить статистику покрытия (что хорошо для морали) и получить больше опыта с базой кодов, в то время как категория 3 - более (часто разочаровывающая) работа, но также дает больше преимуществ. Что вы должны сделать в первую очередь, зависит от того, насколько важны для вас статистика морального состояния и охвата. Категория 4, вероятно, не стоит беспокоиться.
источник
У меня большой опыт работы на унаследованных системах (но не на Java), гораздо больший, чем этот. Я ненавижу быть носителем плохих новостей, твоя проблема - это размер твоей проблемы. Я подозреваю, что вы недооценили это.
Добавление регрессионных тестов в устаревший код - это медленный и дорогой процесс. Многие требования недостаточно хорошо документированы - здесь исправление ошибок, исправление, и, прежде чем вы это узнаете, программное обеспечение определяет свое поведение. Отсутствие тестов означает, что реализация - это все, что нужно пройти, отсутствие тестов для «оспаривания» неявных требований, реализованных в коде.
Если вы попытаетесь быстро получить страховое покрытие, скорее всего, вы срочно отправите работу, наполовину испечете ее и потерпите неудачу. Тесты дадут частичное освещение очевидных вещей, и не дадут полного освещения реальных проблем. Вы убедите менеджеров, которых вы пытаетесь продать, в то, что модульное тестирование не стоит того, что это просто еще одна серебряная пуля, которая не работает.
ИМХО, лучший подход - нацелиться на тестирование. Используйте метрики, интуицию и отчеты о дефектах, чтобы идентифицировать 1% или 10% кода, который создает наибольшее количество проблем. Хит эти модули сильно, и игнорировать остальные. Не пытайтесь делать слишком много, чем меньше, тем лучше.
Реальная цель состоит в том, что «поскольку мы внедрили UT, количество дефектов в тестируемых модулях сократилось до x% от тех, которые не входят в UT» (в идеале x - это число <100).
источник
Мне напомнили о том, что не надо беспокоиться о двери сарая, когда лошадь уже заперта.
Реальность такова, что на самом деле не существует экономически эффективного способа получить хорошее тестовое покрытие для унаследованной системы, конечно же, в короткие сроки. Как упомянул MattNz, это будет очень трудоемкий процесс и в конечном итоге дорогостоящий. Моя интуиция говорит мне, что если вы попытаетесь сделать что-то, чтобы произвести впечатление на руководство, вы, вероятно, создадите новый кошмар обслуживания, потому что пытаетесь показать слишком много слишком быстро, без полного понимания требований, которые вы пытаетесь проверить.
На самом деле, когда вы уже написали код, практически уже поздно эффективно писать тесты без риска пропустить что-то жизненно важное. С другой стороны, вы могли бы сказать, что некоторые тесты лучше, чем никаких тестов, но если это так, сами тесты должны показать, что они повышают ценность системы в целом.
Я бы посоветовал взглянуть на те ключевые области, где вы чувствуете, что что-то «сломано». Я имею в виду, что это может быть ужасно неэффективный код, или то, что вы можете продемонстрировать, ранее было дорогостоящим в обслуживании. Документируйте проблемы, а затем используйте это в качестве отправной точки для введения уровня тестирования, который поможет вам улучшить систему, не предпринимая больших усилий по реинжинирингу. Идея здесь состоит в том, чтобы не играть в догонялки с тестами, а вместо этого вводить тесты, которые помогут вам решить конкретные проблемы. По прошествии некоторого времени посмотрите, сможете ли вы измерить и провести различие между предыдущей стоимостью обслуживания этого раздела кода и текущими усилиями с исправлениями, которые вы применили с их поддерживающими тестами.
Следует помнить, что руководство больше интересуется затратами / выгодами и тем, как это напрямую влияет на их клиентов и, в конечном счете, на их бюджет. Они никогда не заинтересованы в том, чтобы делать что-то просто потому, что это лучше всего делать, если только вы не докажете, что это принесет им пользу, которая им интересна. Если вам удастся показать, что вы улучшаете систему и получаете хорошее тестовое покрытие для работы, которую вы выполняете в настоящее время, руководство, скорее всего, сочтет это эффективным приложением ваших усилий. Это могло бы позволить вам аргументировать аргумент в пользу распространения ваших усилий на другие ключевые области, не требуя либо полного замораживания разработки продукта, либо, что еще хуже, почти невозможного аргументировать переписывание!
источник
Один из способов улучшить охват - написать больше тестов.
Другой способ - уменьшить избыточность в вашем коде таким образом, чтобы существующие тесты фактически охватывали избыточный код, который в настоящее время не рассматривается.
Представьте, что у вас есть 3 кодовых блока, a, b и b ', где b' является дубликатом (точной или почти пропущенной копии) B, и что у вас есть покрытие a и b, но не b 'с тестом T.
Если реорганизовать кодовую базу для устранения b 'путем извлечения общности из b и b' как B, кодовая база теперь выглядит как a, b0, B, b'0, где b0 содержит неразделенный код с b'0 и наоборот. и b0 и b'0 намного меньше, чем B, и вызывают / используют B.
Теперь функциональность программы не изменилась, и ни у одного из них нет теста T, поэтому мы можем снова запустить T и ожидать его прохождения. Теперь рассматривается код a, b0 и B, но не b'0. Кодовая база стала меньше (b'0 меньше, чем b '!), И мы все еще рассмотрим то, что мы изначально охватили. Наш коэффициент покрытия вырос.
Для этого вам нужно найти b, b 'и в идеале B, чтобы включить рефакторинг. Наш инструмент CloneDR может сделать это для многих языков, особенно для Java. Вы говорите, что в вашей кодовой базе много дублированного кода; Это может быть хорошим способом решения этой проблемы.
Как ни странно, акт поиска b и b 'часто увеличивает ваш словарный запас об абстрактных идеях, которые реализует программа. Хотя инструмент не имеет представления о том, что делают b и b, сам факт их выделения из кода, позволяющий просто сосредоточиться на содержимом b и b, часто дает программистам очень хорошее представление о том, какую абстракцию B_abstract реализует клонированный код. , Так что это также улучшает ваше понимание кода. Удостоверьтесь, что вы даете B хорошее имя, когда произносите его, и вы получите лучшее тестовое покрытие и более удобную программу.
источник