简体   繁体   English

如何验证 java.lang.reflect.Method 仅从反射已知被调用在 object

[英]How to verify a java.lang.reflect.Method known only from reflection was called on an object

Given a java.lang.reflect.Method object obtained through reflection, how can I test that this Method was called on a given object?给定通过反射获得的 java.lang.reflect.Method object,我如何测试在给定的 object 上调用了此方法?

Here is an example code:这是一个示例代码:

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();

Now I'd like to check if myMethodIWantToCheck was called on obj .现在我想检查是否在obj上调用了myMethodIWantToCheck

Basically it's the same functionality as verify from Mockito but without knowing the method at compile time.基本上它与 Mockito 的verify功能相同,但在编译时不知道该方法。

Is there any way?有什么办法吗? Any library already implementing this?任何图书馆已经实现了这个?

No, there's apparently no short and easy way to do so using only the libraries provided by the Java SE.不,显然没有简单的方法可以仅使用 Java SE 提供的库。 And I couldn't be happier about this!我对此感到非常高兴!

The naive approach天真的方法

Let's imagine that what you're trying to achieve was actually possible and a supported operation in the java.lang.reflect -API.让我们想象一下,您要实现的目标实际上是可能的,并且在java.lang.reflect中支持操作。 What kind of information and mechanisms would be required to provide such a functionality?提供这样的功能需要什么样的信息和机制? In case one should be able to retrieve whether a certain method has already been invoked (on a certain object) at least once at any time (with no kind of "start delimiter"), the Java Virtual Machine would be required to keep track of any invocation ever made;如果一个人应该能够在任何时候检索某个方法是否已经被调用(在某个对象上)至少一次(没有“开始分隔符”),则需要 Java 虚拟机来跟踪任何调用; effectively forcing it to persist all stack frames ever created, Introducing such a start delimiter may possibly reduce the runtime overhead, but would still require an extremely complex form of stack frame auditing.有效地强制它保留所有创建的堆栈帧,引入这样的起始分隔符可能会减少运行时开销,但仍需要极其复杂的堆栈帧审计形式。 built into every JVM.内置在每个 JVM 中。

How Mockito is doing it Mockito 是如何做到的

But hey, Mockito is able to provide such a functionality, right?但是,嘿,Mockito 能够提供这样的功能,对吧? Indeed, but I think you're underestimating the complexity of the way they're doing that.确实,但我认为你低估了他们这样做的方式的复杂性。

First, there's a very important, conceptual difference between your and Mockito's approach.首先,您的方法和 Mockito 的方法之间存在一个非常重要的概念差异。 It already becomes apparent when taking a look at the very first example on the Mockito website :在查看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();

Users of the framework always have to mock the types of interest first;框架的用户总是必须首先模拟感兴趣的类型; either explicitly like here or in a more implicit manner by using annotations.要么明确地喜欢这里,要么通过使用注释以更隐含的方式。 As I'm not very familiar with the Mockito framework, there may be even more elegant ways to do so;由于我对 Mockito 框架不是很熟悉,因此可能有更优雅的方法可以做到这一点; but it all boils down to the very same concept.但这一切都归结为同一个概念。

But what does "mocking a type" even mean and what should it be good for?但是“模拟类型”甚至意味着什么,它应该有什么用处? Actually, Mockito has to somehow intercept any call that is being made to the object returned by the mocking method (or the other mechanisms, respectively).实际上,Mockito 必须以某种方式拦截对 mocking 方法(或其他机制)返回的 object 进行的任何调用。 Fortunately (keeping the beginning of this post in mind), Mockito isn't able to do so directly, so the developers had to come up with something else: Creating new types dynamically at runtime that are not only delegating the method calls to the actual implementation, but that also keep track of the methods that are being invoked on that particular type.幸运的是(记住这篇文章的开头),Mockito 不能直接这样做,所以开发人员必须想出别的办法:在运行时动态创建新类型,不仅将方法调用委托给实际实现,但它也跟踪在该特定类型上调用的方法。

Looking at the framework's source code , it seems like that the real magic is happening in the org.mockito.internal.creation.bytebuddy package.查看框架的源代码,似乎真正的魔力发生在org.mockito.internal.creation.bytebuddy package 中。 In SubclassBytecodeGenerator , you can find Mockito's type creation logic.SubclassBytecodeGenerator中,您可以找到 Mockito 的类型创建逻辑。 As the package name already implies, Mockito uses the Byte Buddy framework for the bytecode generation and loading process.正如 package 名称已经暗示的那样,Mockito 使用Byte Buddy 框架进行字节码生成和加载过程。

Library support图书馆支持

As you've also asked for a library which you may use to achieve the same behavior: As far as I can tell, there's no really well-known library out there.正如您还要求提供一个可以用来实现相同行为的库:据我所知,那里没有真正知名的库

To be honest: I'm not surprised that that's the case.老实说:我对这种情况并不感到惊讶。 I mean, what should one use such a library for?我的意思是,一个人应该使用这样的图书馆做什么? Checking whether a method has been invoked is something one should do in tests;检查方法是否被调用是测试中应该做的事情; other use cases are quite limited.其他用例非常有限。

So, yeah.是的。 Your options are quite limited, I suppose.我想你的选择非常有限。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM