模拟没有运行时开销的接口的廉价方法

时间:2010-06-22 11:36:32

标签: java proxy code-generation mocking cglib

假设我有一个接口,其中包含许多我想要为测试进行模拟的方法,并且假设我不需要它来做任何事情,我只需要测试中的对象来获得它的实例。例如,我想在一些代码上运行一些性能测试/基准测试,并且不希望这个接口上的方法有所贡献。

有很多工具可以轻松完成,例如

Interface mock = Mockito.mock(Interface.class);
ObjectUnderTest obj = ...
obj.setItem(mock);

或其他什么。

但是,它们都带来了一些我宁愿避免的运行时开销:

  • Mockito记录所有电话,将论证存放起来以供日后验证
  • JMock和其他人(我相信)要求你定义他们要做什么(不是那么重要),然后执行通过各种类型的代理来实际调用方法。
  • 好老的java.lang.reflect.Proxy和朋友们在进入要调用的方法之前,至少要经过堆栈上的一些方法调用,通常是反思性的。

(我愿意纠正这些例子的任何细节,但我相信这个原则是有效的。)

我的目标是接口的“真正的”无操作实现,例如我可以手动编写返回nullfalse0的所有内容。但如果我感到懒惰并且界面有很多方法,那就无济于事。那么,如何在运行时生成并实例化任意接口的这种无操作实现呢?

有一些工具可供使用,例如Powermock,CGLib,它们使用字节码生成,但仅作为较大的模拟/代理上下文的一部分,我还没有想出从内部选择的内容。

好的,所以这个例子可能有点做作,我怀疑代理会对时间产生太大影响,但我现在很好奇如何生成这样一个类。 CGLib,ASM是否容易?


编辑:是的,这是过早的优化,并没有真正需要这样做。在写完这个问题之后,我认为最后一句话并不能说明我对原则上如何做到这一点更感兴趣,并且比我给出的实际用例更容易进入动态类生成。也许从一开始措辞不好。

2 个答案:

答案 0 :(得分:3)

不确定这是否是您正在寻找的,但Eclipse中的“新类”向导允许您构建新类并指定超类和/或接口。如果你允许它,它将自动编码所有接口/抽象方法的虚拟实现(返回null除非void)。这样做非常轻松。

我怀疑其他“大牌”IDE,例如NetBeans和Idea,都有类似的功能。


编辑:

再次查看您的问题,我想知道为什么在处理测试类时您会担心自动代理的性能。在我看来,如果性能是一个问题,你应该测试“真正的”功能,如果你正在处理大多数未实现的类,那么你不应该处于性能重要的测试环境中。

答案 1 :(得分:0)

构建实用程序需要一些工作,但对于没有“边缘情况”(注释等)的基本vanilla Java接口可能不会太难,使用Javassist代码生成在运行时以文本方式创建实现null的类在接口上定义的每个方法的版本。这与Javassist ProxyFactory(或CGLib Enhancer)代理对象不同,后者仍然具有几层间接。我认为直接字节码生成模式在结果类中没有开销。如果你很勇敢,你也可以潜入ASM做同样的事情。