Как проверить, * java .lang.reflect.Method, известный только по отражению, был вызван на объекте - PullRequest
1 голос
/ 03 апреля 2020

Учитывая объект java .lang.reflect.Method, полученный с помощью отражения, как я могу проверить, что этот метод был вызван для данного объекта?

Вот пример кода:

MyClass obj = mock(MyClass.class);
injectInTestedObject(obj, testedObj);

String myMethodIWantToCheckName = retrieveMethodNameBySomeMeans();
Method myMethodIWantToCheck =
  Arrays.asList(MyClass.class.getMethods())
    .stream()
    .filter(method -> method.getName().equals(myMethodIWantToCheckName))
    .findFirst()
    .get();

Теперь я хотел бы проверить, был ли вызван myMethodIWantToCheck на obj.

По сути, это та же функциональность, что и verify от Mockito, но без знания метода во время компиляции.

Есть ли способ? Любая библиотека уже реализует это?

1 Ответ

2 голосов
/ 04 апреля 2020

Нет, очевидно, нет короткого и простого способа сделать это, используя только библиотеки, предоставляемые 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 для генерации и загрузки байт-кода.

Поддержка библиотеки

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

Если честно: я не удивлен, что это так. Я имею в виду, для чего нужно использовать такую ​​библиотеку? Проверка, был ли вызван метод, - это то, что нужно делать в тестах; другие случаи использования весьма ограничены.

Так что, да. Полагаю, ваши возможности весьма ограничены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...