Статьи

Устаревший код для тестируемого кода № 2: метод извлечения

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

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

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

В нашем классе Person у нас есть метод GetZipCode :

1
2
3
4
5
6
7
8
public class Person {
    String street;
 
    public String getZipCode() {
        Directory directory = Directory.getInstance();
        return directory.getZipCodeFromStreet(street);
    }
}

Метод Directory.getInstance () является статическим. Если мы извлечем его в метод getDirectory (в классе Person ) и сделаем этот метод доступным, мы теперь можем его смоделировать .

01
02
03
04
05
06
07
08
09
10
11
12
public class Person {
    String street;
     
    public String getZipCode() {
        Directory directory = getDirectory();
        return directory.getZipCodeFromStreet(street);
    }
     
    protected Directory getDirectory() {
        return Directory.getInstance();
    }
}

Хотя теперь очень легко издеваться над методом getDirectory с помощью Mockito, также было легко издеваться над Directory.getInstance, если мы использовали PowerMockito. Есть ли дополнительная причина для введения нового метода?

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

Есть моменты, когда извлечение помогает нам независимо от насмешного инструмента. Мы можем использовать метод извлечения для упрощения теста, даже до того, как мы его написали. Проще и безопаснее издеваться над одним методом, чем за 3 вызова.

Если наш метод getZipCode выглядел так:

01
02
03
04
05
06
07
08
09
10
public String getZipCode() {
    Address address = new Address();
    address.setStreet(street);
    address.setCountry(country);
    address.setState(state);
    address.setCity(city);
     
    Directory directory = Directory.getInstance(address);
    return directory.GetZipCode();
}

Даже с мощными инструментами подделка экземпляра Address и установка остальных параметров поведения только для извлечения каталога — это довольно большая работа, что означает более длительный тест с длительной настройкой. Если мы извлечем метод getDirectoryFromAddress :

1
2
3
4
public String getZipCode() {
    Directory directory = getDirectoryFromAddress();
    return directory.GetZipCode();
}

Мы получаем более читаемый код, и нам нужно смоделировать только одну строку.

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

Ссылка: Устаревший код к тестируемому коду № 2: Извлеките метод из нашего партнера JCG Джила Зильберфельда в блоге Geek Out of Water .