Экстремальное программирование. Разработка через тестирование | страница 118



Для изоляции изменений можно использовать несколько разных способов. Наиболее часто используется шаблон «Выделение метода» (Extract Method), помимо него также используются «Выделение объекта» (Extract Object) и «Метод в объект» (Method Object).

Миграция данных (Migrate Data)

Как можно перейти от одного представления к другому? Временно дублируйте данные.


Как

Вначале рассмотрим версию «от внутреннего к внешнему». В рамках этого подхода вы изменяете вначале внутреннее представление, а затем внешний интерфейс.

1. Создайте переменную экземпляра в новом формате.

2. Инициализируйте переменную нового формата везде, где инициализируется переменная старого формата.

3. Используйте переменную нового формата везде, где используется переменная старого формата.

4. Удалите старый формат.

5. Измените внешний интерфейс так, чтобы использовать новый формат.

Однако в некоторых ситуациях удобнее сначала изменить API. В этом случае рефакторинг выполняется следующим образом.

1. Добавьте параметр в новом формате.

2. Обеспечьте преобразование параметра в новом формате во внутреннее представление, обладающее старым форматом.

3. Удалите параметр в старом формате.

4. Замените использование старого формата на использование нового формата.

5. Удалите старый формат.


Зачем

Проблема миграции данных возникает каждый раз, когда используется шаблон «От одного ко многим» (One to Many). Предположим, что мы хотим реализовать объект TestSuite, используя шаблон «От одного ко многим» (One to Many). Мы можем начать так:


def testSuite(self):

suite = TestSuite()

suite.add(WasRun("testMethod"))

suite.run(self.result)

assert("1 run, 0 failed" == self.result.summary())


Чтобы реализовать этот тест, начнем с одного элемента test:


class TestSuite:

def add(self, test):

self.test = test

def run(self, result):

self.test.run(result)


Теперь мы приступаем к дублированию данных. Вначале инициализируем коллекцию тестов:


TestSuite

def __init__(self):

self.tests = []


В каждом месте, где инициализируется поле test, добавляем новый тест в коллекцию:


TestSuite

def add(self, test):

self.test = test

self.tests.append(test)


Теперь мы используем коллекцию тестов вместо единичного теста. Исходя из существующего набора тестов данное преобразование можно считать рефакторингом (оно не нарушает семантику), так как в составе коллекции присутствует только один элемент.


TestSuite

def run(self, result):

for test in self.tests:

test.run(result)


Теперь можно удалить не используемую переменную экземпляра test: