Built-in Fake Objects

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

В то время как фиктивные объекты являются идеальными инструментами для модульного тестирования, использование фиктивных фреймворков может превратить ваши модульные тесты в неподдерживаемый беспорядок. Благодаря им мы часто слышим, что “фиктивы плохи” и “фиктивы злы”.

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

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

Возьмем интерфейс Region из jcabi-dynamo в качестве примера (этот отрывок и все остальные в этой статье упрощены для краткости).

Его метод table() возвращает экземпляр интерфейса Table, который имеет собственные методы:

Интерфейс Frame, возвращаемый методом frame(), также имеет собственные методы. И так далее. Для создания правильно замоканного экземпляра интерфейса Region обычно требуется создание десятка других мок-объектов. С помощью Mockito это будет выглядеть так:

И все это является всего лишь опорной конструкцией перед фактическим тестированием.

Допустим, вы разрабатываете проект, который использует jcabi-dynamo для управления данными в DynamoDB. Ваш класс может выглядеть примерно так:

Вы можете себе представить, насколько сложно будет провести модульное тестирование этого класса с использованием Mockito, например. Сначала нам нужно смоделировать интерфейс Region. Затем мы должны имитировать интерфейс Table и убедиться, что он возвращается методом table(). Затем нам нужно имитировать интерфейс Frame и так далее.

Модульный тест будет намного длиннее самого класса. Кроме того, его реальная цель, которая заключается в тестировании получения заработной платы сотрудника, не будет очевидна для читателя.

Более того, когда нам понадобится протестировать аналогичный метод аналогичного класса, нам придется снова начинать моделирование с нуля. Опять же, несколько строк кода, которые будут очень похожи на то, что мы уже написали.

Решение заключается в создании фиктивных классов и их совместной отправке с реальными классами. Именно это делает jcabi-dynamo. Просто посмотрите на его JavaDoc. В нем есть пакет под названием com.jcabi.dynamo.mock, который содержит только фиктивные классы, подходящие только для модульного тестирования.

Несмотря на то, что их единственная цель - оптимизация модульного тестирования, мы отправляем их вместе с кодом для продакшена, в том же JAR-пакете.

Вот как будет выглядеть тест, когда используется фиктивный класс MkRegion:

Этот тест кажется очевидным для меня. Сначала мы создаем фиктивный регион DynamoDB, который работает поверх хранилища H2Data (встроенная база данных H2). Хранилище будет готово для одной таблицы employees с хэш-ключом name и одним атрибутом salary.

Затем мы добавляем запись в таблицу с хэшем Jeff и зарплатой 50000.

Наконец, мы создаем экземпляр класса Employee и проверяем, как он извлекает зарплату из DynamoDB.

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

Кстати, здесь отличная статья на ту же тему: tl;dw: Stop mocking, start testing от Неда Батчелдера.

P.S. Посмотрите также на эту статью по очень похожей теме: Имитация HTTP-сервера в Java.

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-11-18 at 05:31

sixnines availability badge   GitHub stars