如何检测字节码以判断何时执行 catch 子句?

How to instrument the byte code to tell when a catch clause is being executed?

基于Brett Walker's comment to this ,我想知道如何实现。

"If you want to fail the unit test, in the most general sense, when ever a catch clause is executed by the code in this method you are going to have to instrument the byte code to tell you when a catch clause is being executed. This is a complex task. I would not recommend this."

我如何测试某个方法是否执行了 catch 子句? (下面示例中的isCatched()

假设我有以下 class:

public class A {
  public void method() {
    try {
      // some code that may or may not throw an exception
    } catch(Exception e) {
      // do nothing
    }
  }
}

然后在其他地方:

public class CatchTester {
  private A a;
  public CatchTester(A a) {
    this.a = a;
  }
  public boolean isCatched() {
    // how to do this?
  }
}

有两种方法,都需要了解如何操作 Java 字节码。 ASM exist for making manipulating byte codes a little easier. One would then wire in a Java Agent 等工具或编写自定义 class 加载程序,在将 class 字节加载到 JVM 时对其进行修改。

这种方法的一个很好的例子是 https://github.com/google/allocation-instrumenter。 Allocation-Instrumenter 修改了 class 的字节码,以便可以注册一个回调方法,只要发生对象分配就会调用该回调方法。想象一个用于 try/catch 仪器的类似库并不难。

如果你想通过 Instrumentation 检测某个代码是否被执行,你必须修改代码,注入某种日志代码,它会有效地回调一个方法来记录这个代码被命中的事实。然后你可以在检查方法returns.

后立即检查是否存在这样的记录

虽然在每个异常处理程序的开头插入这样的日志记录代码并不难,但问题是在字节码级别上,catch、[=11]之间没有区别=] 或 try(…) 子句。他们最终都定义了异常处理程序,其中一些可能会重新抛出捕获的异常。如果你想排除重新抛出异常的处理程序,你必须跟踪每条可能的代码路径,从异常处理程序的入口开始,检查它是否以正常完成结束或抛出异常,无论是捕获的还是另一个新构造的.

如果只想知道any catch子句是否执行过,情况就简单多了。如果在 method() 执行期间抛出异常但 method() 正常完成,即调用者未收到异常,则 必须 已经有异常处理程序已执行。