Я бы сказал, что это сверху вниз. Скажем, у меня был один PDF-файл, в котором было 4 отдельных документа, и я писал программное обеспечение для разделения их на 4 отдельных документа вместо одного документа; первый тест, который я, вероятно, написал бы:
// Note: Keeping this very abstract
@Test
public void splitsDocumentsAccordingToDocumentType() {
List docs = new DocumentProcessor().split(new SinglePdfWithFourDocs());
assertEquals(4, docs());
...
}
Я бы посчитал, что метод DocumentProcessor.split()
похож на «А» в вашем примере. Теперь я могу реализовать весь алгоритм в одном методе split
и сделать тесты успешными. Мне даже не нужны буквы "B" или "C", верно? Зная, что вы хороший разработчик, и вам не хватает мысли об этом 1500-строчном методе, вы начинаете искать способы реструктуризации своего кода для более подходящего дизайна. Возможно, вы видите, что из этого кода можно выделить два дополнительных объекта (обязанности):
1) Разбор содержимого файла для поиска отдельных документов и
2) Чтение и запись документа из файловой системы
Давайте сначала займемся # 1. Используйте пару рефакторингов «Извлечь метод», чтобы локализовать код, связанный с синтаксическим анализом содержимого, а затем рефакторинг «Извлечь класс», извлекая эти методы в класс с именем, скажем DocumentParser
. Это может быть аналогично «B» в вашем примере. При желании вы можете переместить тесты, связанные с анализом документов, с вашего DocumentProcessorTest
на новый DocumentParserTest
и смоделировать или заглушить DocumentParser
в DocumentProcessorTest
.
Для # 2 это в значительной степени пена, промыть, повторить, и вы получите что-то вроде DocumentSerializer
класса, AKA "C". Вы также можете смоделировать это в своем DocumentProcessorTest
, и теперь у вас нет файлового ввода-вывода, и вы испытали компонент, в котором есть два дополнительных участника, без необходимости разрабатывать весь класс (с отдельными методами). Обратите внимание, что мы выбрали подход извне, который действительно позволяет проводить рефакторинг.
Спасибо