Какие есть инструменты для мокирования статических методов в Java?
Что проверяют
Знаете ли вы, что статику давно умеет мокать сам Mockito, и понимаете ли цену такого теста. Вопрос почти всегда ведёт ко второму: «а почему у вас вообще возникла потребность подменять статический метод». Сильный ответ содержит и инструмент, и мысль о том, как обойтись без него.
Как отвечать
Начните с актуального инструмента, а не с исторического:
Mockito.mockStatic: появился в Mockito 3.4.0 и работает на inline mock maker, который в Mockito 5.x включён по умолчанию, отдельная зависимостьmockito-inlineбольше не нужна;- как выглядит:
try (MockedStatic<Foo> m = mockStatic(Foo.class)) { m.when(Foo::bar).thenReturn("x"); ... }, проверки черезm.verify(() -> Foo.bar()); - область действия: подмена живёт только в текущем потоке и только внутри блока. Не закрыли
MockedStatic, и следующий тест в этом потоке увидит заглушку, а повторная регистрация того же класса упадёт с ошибкой о том, что статик-мок уже зарегистрирован; - PowerMock: умеет статику, финальные классы и конструкторы через свой загрузчик классов, но развитие остановилось, поддержки JUnit 5 нет, и на свежих JDK он ломается;
- JMockit:
MockUpи@Mock, гибко, но синтаксис специфичный и команда его обычно не знает; - среда: inline mock maker подключает Java-агент на лету, а с JDK 21 такая загрузка печатает предупреждение, которое гасят флагом
-XX:+EnableDynamicAgentLoading.
Закончите альтернативами, их и ждут: обернуть чужую статику своим интерфейсом и подменять его, брать время через Clock вместо LocalDate.now(), а свой статический хелпер сделать обычным классом с внедрением зависимости.
Где спотыкаются
Называют PowerMock первым и единственным вариантом. Это выдаёт опыт, остановившийся на Mockito 2.x, и приводит к разговору про то, зачем в проекте два фреймворка сразу.
Открывают MockedStatic в поле класса или в @BeforeEach без закрытия. Тесты начинают влиять друг на друга, а параллельный прогон даёт плавающие падения, которые ищут потом днями.
Мокают статику вместо того, чтобы починить дизайн. Если тест не пишется без подмены System.currentTimeMillis() или статического синглтона, проблема в коде, и эту мысль от вас и ждут.