Нет, очевидно, нет короткого и простого способа сделать это, используя только библиотеки, предоставляемые Java SE. И я не мог бы быть счастливее об этом!
наивный подход
Давайте представим, что то, что вы пытаетесь достичь, действительно возможно и поддерживается операция в java.lang.reflect
-API. Какая информация и механизмы потребуются для обеспечения такой функциональности? В случае, если нужно иметь возможность узнать, был ли определенный метод уже вызван (для определенного объекта) хотя бы один раз в любое время (без какого-либо «начального разделителя»), виртуальная машина Java должна будет сохранять отслеживание любого вызова, когда-либо сделанного; эффективно заставляя его сохранять все когда-либо созданные кадры стека! Введение такого начального разделителя может, возможно, снизить накладные расходы времени выполнения, но все равно потребует чрезвычайно сложной формы аудита стекового фрейма, встроенного в каждую JVM.
Как это делает Mockito
Но, эй, Mockito способен предоставить такую функциональность, верно? Действительно, но я думаю, что вы недооцениваете сложность того, как они это делают.
Во-первых, существует очень важное концептуальное различие между вашим подходом и подходом Мокито. Это уже становится очевидным, если взглянуть на самый первый пример на веб-сайте Mockito :
import static org.mockito.Mockito.*;
// mock creation
List mockedList = mock(List.class);
// using mock object - it does not throw any "unexpected interaction" exception
mockedList.add("one");
mockedList.clear();
// selective, explicit, highly readable verification
verify(mockedList).add("one");
verify(mockedList).clear();
Пользователи фреймворка всегда должны сначала высмеивать интересующие их типы; либо явно, как здесь, либо более неявно, используя аннотации. Поскольку я не очень знаком с фреймворком Mockito, могут быть даже более элегантные способы сделать это; но все сводится к одной и той же концепции.
Но что вообще означает "издеваться над типом" и для чего он должен быть хорош? На самом деле, Mockito должен каким-то образом перехватывать любой вызов, сделанный объекту, возвращаемому методом mocking (или другими механизмами, соответственно). К счастью (имея в виду начало этого поста), Mockito не может сделать это напрямую, поэтому разработчикам пришлось придумать что-то еще: динамически создавать новые типы во время выполнения, которые не только делегируют вызовы методов фактическим реализации, но также отслеживают методы, которые вызываются для этого конкретного типа.
Глядя на исходный код платформы , кажется, что real magi c происходит в пакете org.mockito.internal.creation.bytebuddy
. В SubclassBytecodeGenerator
вы можете найти логику создания типов Mockito c. Как уже подразумевается из названия пакета, Mockito использует Byte Buddy Framework для генерации и загрузки байт-кода.
Поддержка библиотеки
Как вы также просили библиотеку который вы можете использовать для достижения того же поведения: насколько я могу судить, действительно известной библиотеки не существует.
Если честно: я не удивлен, что это так. Я имею в виду, для чего нужно использовать такую библиотеку? Проверка, был ли вызван метод, - это то, что нужно делать в тестах; другие случаи использования весьма ограничены.
Так что, да. Полагаю, ваши возможности весьма ограничены.