Статьи

Подробнее о создании заглушек для устаревшего кода — Методы тестирования 7

В моем последнем блоге я говорил о том, как работать с классом SitePropertiesManager с плохим поведением (1) и как создавать заглушки путем извлечения интерфейса. Но что происходит, когда у вас нет доступа к исходному коду унаследованного класса, поскольку он заблокирован внутри стороннего файла JAR? Ответ — одна из тех вещей, о которых вы действительно не думаете, но когда вы видите это, вы понимаете, что это довольно очевидно.

Чтобы продемонстрировать это, я собираюсь переписать код из моего последнего блога   (2) это тестирует мой простой AddressService . Сценарий тот же, AddressService должен загрузить свойство сайта и решить, стоит ли возвращать адрес:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
public Address findAddress(int id) {
 
    logger.info("In Address Service with id: " + id);
 
    Address address = Address.INVALID_ADDRESS;
 
    if (isAddressServiceEnabled()) {
      address = addressDao.findAddress(id);
      address = businessMethod(address);
    }
 
    logger.info("Leaving Address Service with id: " + id);
    return address;
  }
 
  private boolean isAddressServiceEnabled() {
 
    return new Boolean(propManager.findProperty("address.enabled"));
  }

… кроме того, я собираюсь притвориться, что SitePropertiesManager заблокирован внутри файла JAR.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
public class StubSitePropertiesUsingInheritance extends SitePropertiesManager {
 
  private final Map<String, String> propMap = new HashMap<String, String>();
 
  public void setProperty(String key, String value) {
    propMap.put(key, value);
  }
 
  @Override
  public String findProperty(String propertyName) {
    return propMap.get(propertyName);
  }
}

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class LegacyAddressServiceUsingInheritanceTest {
 
  private StubAddressDao addressDao;
 
  private StubSitePropertiesUsingInheritance stubProperties;
 
  private LegacyAddressService instance;
 
  @Before
  public void setUp() {
    instance = new LegacyAddressService();
 
    stubProperties = new StubSitePropertiesUsingInheritance();
    instance.setPropertiesManager(stubProperties);
  }
 
  @Test
  public void testAddressSiteProperties_AddressServiceDisabled() {
 
    /* Set up the AddressDAO Stubb for this test */
    Address address = new Address(1, "15 My Street", "My Town", "POSTCODE", "My Country");
    addressDao = new StubAddressDao(address);
    instance.setAddressDao(addressDao);
 
    stubProperties.setProperty("address.enabled", "false");
 
    Address expected = Address.INVALID_ADDRESS;
    Address result = instance.findAddress(1);
 
    assertEquals(expected, result);
  }
 
  @Test
  public void testAddressSiteProperties_AddressServiceEnabled() {
 
    /* Set up the AddressDAO Stubb for this test */
    Address address = new Address(1, "15 My Street", "My Town", "POSTCODE", "My Country");
    addressDao = new StubAddressDao(address);
    instance.setAddressDao(addressDao);
 
    stubProperties.setProperty("address.enabled", "true");
 
    Address result = instance.findAddress(1);
 
    assertEquals(address, result);
  }
}

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


(1) Разработан без учета модульного тестирования.
(2) Исходный код доступен на GitHub по адресу:

мерзавец: //github.com/roghughe/captaindebug.git

Ссылка: Подробнее о создании заглушек для устаревшего кода — Методы тестирования 7 от нашего партнера по JCG Роджера Хьюза в блоге Captain Debug .

Статьи по Теме :