Мокирование класса против мокирования его интерфейса
У меня есть задача для модульного тестирования, в рамках которой мне нужно замокировать несколько зависимостей. Одна из зависимостей — это класс, который реализует интерфейс:
public class DataAccessImpl implements DataAccess {
...
}
Мне необходимо настроить объект-заглушку (mock) этого класса, который будет возвращать определенные значения при передаче ему определенных параметров.
Теперь у меня возникла неуверенность, что лучше — замокировать интерфейс или класс, то есть:
DataAccess client = mock(DataAccess.class);
или
DataAccess client = mock(DataAccessImpl.class);
Имеет ли это значение с точки зрения тестирования? Какой подход будет предпочтительнее?
5 ответ(ов)
Вы должны создать мок интерфейса, так как это поможет убедиться, что вы соблюдаете принцип подстановки Лисков (Liskov Substitution Principle). Подробнее о принципах объектно-ориентированного проектирования вы можете прочитать здесь: https://stackoverflow.com/a/56904/3571100.
Если вы используете его исключительно через интерфейс и это не частичный мок, то между ними нет никакой разницы, кроме вашего внутреннего ощущения. Мокая класс, вы также замокаете неиспользуемые публичные методы, если они есть в классе, но это не является серьезной проблемой для рассмотрения.
В вашем случае это может не иметь большого значения, но предпочтительным подходом является мокирование интерфейсов. Обычно, если вы следуете практике TDD (разработка через тестирование), вы можете писать свои юнит-тесты еще до реализации конкретных классов. Таким образом, даже если у вас нет конкретного класса DataAccessImpl
, вы все равно сможете писать юнит-тесты, используя ваш интерфейс DataAccess
.
Кроме того, у фреймворков для мокирования есть ограничения при мокировании классов, и некоторые из них по умолчанию мокируют только интерфейсы.
В большинстве случаев технически нет разницы, и вы можете создавать моки как для классов, так и для интерфейсов. Однако концептуально лучше использовать интерфейсы из-за лучшей абстракции.
Это зависит от ситуации. Если ваш код зависит от конкретного класса, а не от интерфейса, вам необходимо создать мок этого класса, чтобы написать корректный модульный тест.
Как протестировать класс с приватными методами, полями или внутренними классами?
Как замокировать методы с возвращаемым типом void с помощью Mockito
Как проверить, что конкретный метод не был вызван, используя Mockito?
Можно ли с помощью Mockito захватывать аргументы метода, вызываемого несколько раз?
Можно ли создать мок-объект, который реализует несколько интерфейсов с помощью EasyMock?