Предпосылка приоритета трансформации - это руководство для более аналитического подхода к разработке через тестирование. Это набор правил, которые должны помочь в написании тестов TDD.

Если вы раньше не слышали о TPP, но знакомы с TDD, то основная посылка (не каламбур) такая же. Вы всегда должны вносить минимально возможные изменения. Однако порядок, в котором вы применяете изменения, имеет большое значение для качества и количества производимых тестов. Вот как это объясняет дядя Боб:

«У рефакторинга есть аналоги, называемые преобразованиями. Рефакторинг - это простые операции, которые изменяют структуру кода без изменения его поведения. Преобразования - это простые операции, изменяющие поведение кода. Преобразования могут использоваться как единственное средство для прохождения текущего неуспешного теста в цикле красный / зеленый / рефакторинг. Преобразования имеют приоритет или предпочтительный порядок, который, если его поддерживать в соответствии с порядком проведения тестов, предотвратит тупиковые ситуации или длительные простои в цикле красный / зеленый / рефакторинг ».

- « Дядя Боб Мартин», « Предпосылка трансформации , Блог дяди Боба

Правила

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

Фрагменты кода написаны на Python. Первоначальная общая идея заключалась в том, чтобы представить, что вы работаете над программой, которая переводит двузначный код страны в название страны, чтобы не было необходимости в большом контексте кода для понимания каждого из преобразований.

Важно понимать, что примеры приведены не по порядку, а сами тесты не будут работать вместе. Каждый шаг отображается так:

# The existing code

# The red (failing) test.
# The new code using that transformation.
# It will also make the test go green (pass).

1. {} → ноль

Преобразуйте без кода во что-то, что возвращает нулевое значение.

без кода

def test_bad_country_code_returns_none():
    assert country_from_code(None) is None
def country_from_code(code):
    return None

2. ноль → константа

def country_from_code(code):
    return None

def test_country_is_a_string():
    assert type(country_from_code('AU')) is str
def country_from_code(code):
    return “"

3. константа → константа +

Преобразование от простой константы к более сложной константе.

def country_from_code(code):
    return ""

def test_au_is_australia():
    assert country_from_code('AU') == ‘Australia'
def country_from_code(code):
    return “Australia"

4. константа → скаляр

Замена константы переменной или аргументом.

def country_from_code(code):
    return “"

def test_au_is_australia():
    assert country_from_code('AU') == ‘Australia'
def country_from_code(code):
    country = "Australia"
    return country

5. выписка → выписки

Добавление еще безусловных утверждений.

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

def country_from_code(code):
    country = "australia"
return country

def test_au_is_australia():
    assert country_from_code('AU') == ‘Australia'
def country_from_code(code):
    country = "australia"
    country = country[0].upper() + country[1:]
return country

6. безусловный → если

Разделение пути выполнения. Также допустимо использовать вместо этого троичную систему.

def country_from_code(code):
    return “Australia"

def test_es_is_spain():
    assert country_from_code('ES') == ‘Spain'
def country_from_code(code):
    if (code == 'ES'):
        return "Spain"
    return “Australia"

7. скаляр → массив

def country_from_code(code):
    if (code == 'ES'):
        return "Spain"
    return “Australia"

def test_dk_is_denmark():
    assert country_from_code('DK') == ‘Denmark'
def country_from_code(code):
    countries = ('AU', 'Australia', 'DK', 'Denmark', 'ES', 'Spain')
    return countries[countries.index(code) + 1]

8. массив → контейнер

Обычно это означает преобразование простого массива в более сложную коллекцию, такую ​​как словарь или массив объектов.

def country_from_code(code):
    countries = ('AU', 'Australia', 'DK', 'Denmark', 'ES', 'Spain')
    return countries[countries.index(code) + 1]

def test_mx_is_mexico():
    assert country_from_code('MX') == ‘Mexico'
def country_from_code(code):
    countries = {
        'AU': 'Australia', 'DK': 'Denmark', 'ES': 'Spain', 'MX': 'Mexico'
    }
return countries[code]

9. оператор → хвостовая рекурсия

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

Хвостовая рекурсия означает, что последняя инструкция (обычно возвращаемое значение) является рекурсивным вызовом.

def country_from_code(code):
    countries = ('AU', 'Australia', 'DK', 'Denmark')
    return countries[countries.index(code) + 1]

def test_nz_is_new_zealand():
    assert country_from_code('NZ') == 'New Zealand’
def country_from_code(code, index=0):
    countries = ('AU', 'Australia', 'DK', 'Denmark', 'NZ', 'New Zealand')
if countries[index] == code:
        return countries[index + 1]
return country_from_code(code, index + 2)

10. если → пока

Преобразуйте бинарный оператор ветвления (if, если, если, ternary и т. Д.) В цикл (while, do, for и т. Д.).

def country_from_code(code):
    if (code == 'ES'):
        return "Spain"
return “Australia"

def test_th_is_thailand():
    assert country_from_code('TH') == ‘Thailand'
def country_from_code(code):
    countries = (('AU', 'Australia'), ('ES', 'Spain'), ('TH', 'Thailand'))
for country in countries:
        if country[0] == code:
            return country[1]
return None

11. оператор → без хвостовой рекурсии

Не хвостовая рекурсия означает, что последняя инструкция (обычно возвращаемое значение) не является рекурсивным вызовом.

def country_from_code(code):
    countries = ('AU', 'Australia', 'DK', 'Denmark')
return countries[countries.index(code) + 1]

def test_de_is_germany():
    assert country_from_code('DE') == ‘Germany'
def country_from_code(code, index=0):
    countries = ('AU', 'Australia', 'DK', 'Denmark', 'DE', 'Germany')
if countries[index] != code:
        country = country_from_code(code, index + 2)
    else:
        country = countries[index + 1]
return country

12. выражение → функция

Замена выражения функцией или алгоритмом.

def country_from_code(code):
    countries = {
        'AU': 'Australia', 'DK': 'Denmark', 'ES': 'Spain'
    }
    return countries[code]

def test_it_is_italy():
    assert country_from_code('IT') == ‘Italy'
def get_country_codes():
    return {
        'AU': 'Australia', 'DK': 'Denmark', 'ES': 'Spain', 'IT': 'Italy'
    }
def country_from_code(code):
    countries = get_country_codes()
return countries[code]

13. переменная → присвоение

Замена значения переменной.

def country_from_code(code):
    if code == 'ES':
        return 'Spain'
return ‘Australia'

def test_dk_is_denmark():
    assert country_from_code('DK') == ‘Denmark'
def country_from_code(code):
    country = 'Australia'
    if code == 'ES':
        country = 'Spain'
    if code == 'DK':
        country = 'Denmark'
return country

14. чехол

Добавление case (или еще) к существующему переключателю или if.

def country_from_code(code):
    if (code == 'ES'):
        return "Spain"
return “Australia"

def test_dk_is_denmark():
    assert country_from_code('DK') == ‘Denmark'
def country_from_code(code):
    if (code == 'ES'):
        return "Spain"
if (code == 'DK'):
        return "Denmark"
return “Australia"

Дополнительная информация

Я рекомендую вам прочитать оригинальную статью от дяди Боба.

Я упоминал выше, что эта статья действительно требует гораздо большего внимания, чтобы предложить лучшие примеры для некоторых преобразований, пожалуйста, свяжитесь со мной, если у вас есть какие-либо идеи.

Первоначально опубликовано на http://elliot.land 7 мая 2016 г.