在 Eclipse Debug 中使用 JUnit 运行测试用例时禁用的拖放到帧功能

2022-09-04 21:44:38

环境:Linux,Eclipse Juno,Java 7,JUnit

当一个简单的应用程序(带有main方法的java类)在调试模式下运行时,“拖放到帧”功能在Eclipse中工作正常。但是,如果从 junit 测试用例调用相同的方法,则 Eclipse 中的“拖放到帧”功能将被禁用。从文档中

请注意,仅当当前 VM 支持拖放到帧并且所选堆栈帧不是顶部帧或本机方法中的帧时,此命令才可用。

正如我们从调试窗口中的堆栈帧中看到的那样,当运行 junit 测试用例时,有一个帧 'NativeMethodAccessorImpl.invoke' 是原生的。我假设这是“拖放到帧”被禁用的原因。

让我知道这个推理是否正确,如果是,是否有任何可用的解决方法来克服这个问题。


答案 1

我在Windows下使用Eclipse Luna,Java 7。情况仍然如前所述:对于紧跟在“NativeMethodAccessorImpl.invoke”帧之后的测试方法,“拖放到帧”被禁用。“拖放到帧”的禁用状态绑定到 类 中相应的方法,(在我的发行版中)部分。方法支持DropToFrame() 检查是否可以删除特定帧,并进行测试canDropToFrame()supportsDropToFrame()org.eclipse.jdt.internal.debug.core.model.JDIStackFrameplugins/org.eclipse.jdt.debug_3.8.102.v20150115-1323/jdimodel.jar

  1. JVM 必须支持丢帧
  2. 框架不能是最上面的框架
  3. 框架不能是本机的
  4. 前一帧不得为本机

因此,拉梅什的假设是正确的。这是测试 3 + 4 的原始代码片段:

int index = 0;
JDIStackFrame frame = null;
while (index < frames.size()) {
    frame = (JDIStackFrame) frames.get(index);
    index++;
    if (frame.isNative()) {
        return false;
    }
    if (frame.equals(this)) {
        if (jdkSupport) {
            // JDK 1.4 VMs are currently unable to pop the
            // frame directly above a native frame
            if (index < frames.size()
                    && ((JDIStackFrame) frames.get(index))
                            .isNative()) {
                return false;
            }
        }
        return true;
    }
}

该注释表明它是用JDK编写的1.4次,因此也许在此期间,JVM现在也可以将帧丢弃在本机帧之上。

我创建了一个JDIStackFrame的修补版本,它跳过了测试4。现在,在 Junit 测试方法中暂停时,如预期的那样,启用了“拖放到帧”。

但是当实际删除帧时,我收到一个错误消息框,其中指出“com.sun.jdi.InternalException:在回复中收到错误代码:32发生弹出堆栈帧”。

我假设这是一个JDWP错误代码。因此,这样的“Drop to frame”似乎在JDK 1.7中不起作用(不知道1.8),而且它不是Eclipse的事情。


答案 2

这是一个旧的,但就目前而言,这仍然是Eclipse 2018-09,Java 1.8和testng作为测试运行程序的问题。解决方法(简单明了)是将测试的内容提取到另一种方法中,对其进行调试,然后将其内联回去。例如:

@Test
public void test() {
    // test goes here
    assertTrue(true);
}

可以使用重构快捷方式来加快速度:选择测试的主体,按Alt + Shift + M,输入名称“inner”,结果是:

@Test
public void test() {
    inner();
}

private void inner() {
    // test goes here and 'drop-to-frame' works well
    assertTrue(true);
}

完成调试后,通过在 inner() 中按 Alt+Shift+I 将其内联回来。