java - 当测试在完全相同的语句处崩溃时,为什么调用堆栈会不同?

标签 java reflection junit

对于一个研究项目,我试图弄清楚单元测试(用 JUnit 编写)在不同上下文中执行时是否表现不同。为此,我做了两件事:首先,我使用自定义 JUnit 运行器运行程序的整个测试套件,然后使用相同的自定义 JUnit 运行器运行单个测试(为什么这有意义并不重要,只需接受它即可)现在)。当测试失败时,我会记录 JUnit 报告的整个异常堆栈跟踪,然后比较两次运行之间的堆栈跟踪。

这样做时,我偶然发现了一些我无法解释的奇怪现象。下面是以这种方式记录的两个堆栈跟踪的两个摘录。

运行整个测试套件时记录的堆栈跟踪:

org.fest.swing.edt.GuiActionRunner.resultOf(GuiActionRunner.java:126)
org.fest.swing.edt.GuiActionRunner.execute(GuiActionRunner.java:73)
net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.AbstractNumericDataTypeUITest.constructTestFrameInEDT(AbstractNumericDataTypeUITest.java:98)
net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.AbstractNumericDataTypeUITest.setUp(AbstractNumericDataTypeUITest.java:81)
sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source) - sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:616)
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)

运行单个测试时记录的堆栈跟踪:

org.fest.swing.edt.GuiActionRunner.resultOf(GuiActionRunner.java:126)
org.fest.swing.edt.GuiActionRunner.execute(GuiActionRunner.java:73)
net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.AbstractNumericDataTypeUITest.constructTestFrameInEDT(AbstractNumericDataTypeUITest.java:98)
net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.AbstractNumericDataTypeUITest.setUp(AbstractNumericDataTypeUITest.java:81)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:616)
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)

两个堆栈跟踪都显示崩溃前的最后几个条目,从最后一个公共(public)语句开始。显然,在 JDK/VM 的反射实现中的某个地方,这两种情况之间的行为有所不同。

我的问题是为什么?

我推测这与虚拟机缓存早期反射调用的内容或其他内容有关,但我真的不知道。了解这一点很重要,因为我必须弄清楚这种情况是否会在每次运行单个测试时发生(因此我可以忽略它),或者这是否与我正在运行的具体测试。

我知道这相当模糊,但我们将不胜感激。

最佳答案

这是因为Sun/Oracle JVM(其他我不知道)优化了反射调用。从 1.4 开始,JVM 生成字节码来桥接对被调用方法的反射调用。因为并不是所有的事情在编译时都是已知的,所以它必须在运行时完成。

类(class)MethodAccessorGenerator生成 GenelatedMethodAccessor1

我从 NativeMethodAccessorImpl 的评论中发现的提示:

仅用于方法的前几次调用;之后,切换到基于字节码的实现

您是否在一个 Java VM 的生命周期中运行该套件和单个测试?

关于java - 当测试在完全相同的语句处崩溃时,为什么调用堆栈会不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12046114/

相关文章:

java - 如何将每个测试嵌入到包装器逻辑中?

java - 未找到测试运行程序 JUnit 4 的测试

java - Ant 中的字符串分组和计数

c++ - 是否可以对使用 Boost Hana 的方法进行内省(introspection)?

c# - 使用反射打印自己的方法名、类库(可移植)

java - 导入 org.junit.Assert 时出错

java - 使用 Java 函数而不是普通方法的好处?

java - 从辅助函数抛出异常

java - GWT 中的用户服务

java - 将整数转换为长整数