Mockito 是借助什么技术来 mock final 类和 final 方法的
Mockito 借助 Java Agent 和 字节码操作 技术来实现对 final
类和 final
方法的 mock。具体来说,它主要依赖于以下两个关键技术:
1. Java Agent (Instrumentation API)
Mockito 通过使用 Java Agent 来实现运行时的字节码操作,这允许在程序加载类时修改类的字节码行为,从而突破 final
类和 final
方法的限制。
-
Java Agent 是 Java 提供的一种机制,允许在 JVM 中通过 Instrumentation API 动态地修改类字节码的定义。通过
mock-maker-inline
配置,Mockito 使用 Java Agent 来修改目标类的字节码,使得final
类或final
方法可以被 mock。 -
Mockito 使用的
mock-maker-inline
工具本质上是通过使用 Java Instrumentation 技术来在运行时修改类的字节码,使得final
修饰符在创建 mock 时无效。
2. Bytecode Manipulation (字节码操作)
Mockito 还使用了 字节码操作 库,通常是 Byte Buddy,来动态生成 mock 对象。通过 Byte Buddy,Mockito 可以修改类的字节码结构,包括取消 final
修饰符的影响,从而允许创建 mock 对象并对 final
方法进行模拟。
- Byte Buddy 是一个用于操作和生成 Java 字节码的库。Mockito 在 2.x 版本中选择 Byte Buddy 作为其主要字节码生成工具。它的任务是创建与被 mock 对象匹配的动态代理类,并根据 Mockito 的要求替换和模拟方法。
3. Class Redefinition and Transformation
Mockito 使用 类重定义 和 类转换 技术来处理已经加载的类。通过 mock-maker-inline
,它在类加载时使用 Java Instrumentation API 将 final
类和方法修改为可以被 mock 的普通类和方法。
当使用 Mockito 的 inline
mock maker 时,类的定义在运行时被改变,这使得即使是 final
方法或类也可以被 mock。这种改变是在类被 JVM 加载前完成的,确保程序运行时能够成功 mock final
类和方法。
技术工作原理总结:
-
Java Agent (Instrumentation) 允许在类加载时修改其字节码定义,使得即使是
final
类和方法也可以在运行时被改变。 -
Byte Buddy 等字节码操作库用于动态生成代理类和方法,将
final
类和方法从其修饰符限制中释放,允许其行为在测试时被模拟或替换。 -
Class Redefinition (类重定义) 技术允许 Mockito 在类加载时修改类的定义,以支持对
final
类和方法的 mock。
为什么使用 Java Agent 和 Byte Buddy?
-
兼容性和灵活性:这些技术允许 Mockito 处理几乎所有类型的类,无论它们是
final
还是非final
,并且能与标准 Java 代码无缝兼容。Java Instrumentation 和 Byte Buddy 可以以最小的性能开销实现动态代理和字节码修改。 -
无需修改源代码:Mockito 使用 Java Agent 和字节码操作,可以在不修改源代码的前提下 mock
final
类和方法。这使得测试过程更加灵活。
总结
Mockito 使用 Java Agent (Instrumentation API) 和 字节码操作库(如 Byte Buddy) 来实现对 final
类和 final
方法的 mock。通过 mock-maker-inline 机制,Mockito 在类加载时动态修改字节码,从而移除 final
限制,使得这些类和方法可以在单元测试中被 mock。