The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:
Когда я начинаю повторяться в методах модульного тестирования, создавая одни и те же объекты и подготавливая данные для запуска теста, я разочаровываюсь в своем дизайне. Длинные методы тестирования с большим количеством дублирования кода выглядят неправильно. Чтобы упростить их и сократить, существует в основном два варианта, по крайней мере в Java: 1) закрытые свойства, инициализированные через @Before
и @BeforeClass
, и 2) закрытые статические методы. Оба варианта выглядят для меня противоречащими ООП, и я думаю, что есть альтернатива. Позвольте мне объяснить.
JUnit официально предлагает тестовый фикстур:
Я думаю, что очевидно, что делает этот тест. Сначала в prepare()
он создает “тестовый фикстур” типа Folder
. Это используется во всех трех тестах в качестве аргумента для конструктора Metrics
. Реальным классом, который здесь тестируется, является Metrics
, а this.folder
- это то, что нам нужно для его тестирования.
Что не так с этим тестом? Есть одна серьезная проблема: связность между тестовыми методами. Тестовые методы (и все тесты вообще) должны быть полностью изолированы друг от друга. Это означает, что изменение одного теста не должно влиять на другие. В этом примере это не так. Когда я хочу изменить тест countsWords()
, мне приходится изменять внутренности before()
, что повлияет на другой метод в “классе” теста.
Со всем уважением к JUnit, идея создания тестовых фикстур в @Before
и @After
неправильна, главным образом потому, что это побуждает разработчиков к связыванию тестовых методов.
Вот как мы можем улучшить наш тест и изолировать тестовые методы:
Выглядит лучше сейчас? Мы еще не достигли цели, но наши тестовые методы теперь полностью изолированы. Если я хочу изменить один из них, я не буду влиять на остальные, потому что передаю все конфигурационные параметры в частный статический вспомогательный (!) метод folder()
.
Вспомогательный метод, да? Да, что-то нехорошее.
Основная проблема этого дизайна, хотя он намного лучше предыдущего, заключается в том, что он не предотвращает дублирование кода между “классами” тестов. Если мне понадобится похожая фиктивная структура тестового типа Folder
в другом тестовом случае, мне придется переместить этот статический метод туда. Или, что еще хуже, мне придется создать вспомогательный класс. Да, в объектно-ориентированном программировании нет ничего хуже вспомогательных классов.
Гораздо лучшим решением было бы использование “фальшивых” объектов вместо частных статических вспомогательных средств. Вот как. Сначала мы создаем фальшивый класс и помещаем его в src/main/java
. Этот класс может использоваться в тестах и также в производственном коде, если необходимо (Fk
для “фейка”):
Вот как будет выглядеть наш тест сейчас:
Что вы думаете? Разве это не лучше, чем то, что предлагает JUnit? Разве это не более многоразовое и расширяемое, чем утилитарные методы?
Подводя итог, я считаю, что создание опоры в модульном тестировании должно осуществляться с помощью фиктивных объектов, которые поставляются вместе с продуктовым кодом.
Translated by ChatGPT gpt-3.5-turbo/42 on 2023-11-28 at 14:41