13

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

当一个简单的应用程序(一个带有 main 方法的 java 类)在调试模式下运行时,'Drop to Frame' 功能在 Eclipse 中运行良好。但是,如果从 junit 测试用例调用相同的方法,则在 Eclipse 中禁用“Drop to Frame”功能。从文档

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

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

让我知道这个推理是否正确,如果是的话,有什么办法可以解决这个问题。

4

3 回答 3

10

我在 Windows 下使用 Eclipse Luna,Java 7。情况仍然如所描述的那样:对于紧跟在“NativeMethodAccessorImpl.invoke”框架之后的测试方法,“Drop to frame”被禁用。“Drop to frame”的禁用状态绑定到类中canDropToFrame()各自的方法,(在我的发行版中)部分。方法 supportsDropToFrame() 检查是否可以丢弃特定帧,并测试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 测试方法中暂停时,“Drop to frame”已启用,正如预期的那样。

但是当实际丢弃帧时,我收到一个错误消息框,上面写着“com.sun.jdi.InternalException: Got error code in reply: 32 occurred popping stack frame”。

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

于 2015-06-07T14:00:46.437 回答
1

@Test我一直通过在函数和可以将帧放入的thunk之间进行拆分来处理这个问题。

在 JDK-8 之前,我会这样做:

@Test
public void testSomeFooInBar() {
    drop_to_frame_testSomeFooInBar();
}

private void drop_to_frame_testSomeFooInBar() {
    assertTrue(somethingOrWhatever);
}

尽管它很冗长,但我坚持/坚持在测试函数之后调用我的thunk,名称表明它们的用途(“跳转/下降到帧”)。这总是必要的,因为总是有人在不阅读评论的情况下进行“重构”,并开始将 thunk 删除为“不必要的”。

使用 JDK 8 及更高版本,我这样做:

@Test
public void testSomeFooInBar() {
    final Runnable drop_to_frame = () -> {
        assertTrue(somethingOrWhatever);
    };
    jump_to_frame.run();
}

更简单。Eclipse 将允许您在可运行的 lambda 中设置断点,并根据需要多次放入帧(假设您的逻辑足够可重入。)

于 2021-02-02T20:04:01.710 回答
1

这是一个旧问题,但目前这仍然是 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 将其内联。

于 2018-10-17T09:17:41.617 回答