【问题标题】:How are Exception classes linked at compilation time in JavaJava中的异常类如何在编译时链接
【发布时间】:2014-05-19 19:44:49
【问题描述】:

作为介绍使用 Java 进行面向对象编程的一部分,我们进行了一次大型(20-36 小时)实践练习 - 今年基于俄罗斯方块。学生遵循指南解释 - 通过文本描述和 uml 类图 - 如何实现他们的游戏。连接到本指南的是一个运行一组单元测试(使用 TestNg 编写)以检查其实现是否符合说明的工具。单元测试使用 100% 符合的代码版本进行预编译,并通过显示测试结果的自定义用户界面启动。执行的测试数量取决于学生达到的部分。

单元测试类的结构都类似:

public static void classExists(String fullClassName) {
    try {
        @SuppressWarnings("unused")
        Class<?> clazz = Class.forName(fullClassName);
    } catch (ClassNotFoundException cnfe) {
        fail(fullClassName + " could not be found on the classpath.");
    }
}
  1. 测试类是否存在

  2. 如果 (1) 成功:测试类可见性

  3. 如果(2)成功:测试方法/属性是否存在

  4. 如果 (3) 成功:测试方法的功能

这很好用,除了一个扩展 Exception 的类,如果我们在测试 (4) 时写:

BloxException be = new BloxException("Message",value);

测试按预期工作,特别是如果 BloxException 不存在,测试 (1) 失败并且其他测试没有执行,但是如果我们尝试抛出异常:

throw new BloxException("Message", value);

测试未执行,因为 TestNg 找不到类 BloxException。 我们假设这是由于Java如何编译上面的两行代码,谁能给我详细说明为什么当我们抛出异常时我们需要类,但是如果我们创建一个新的异常,我们不需要代码来执行测试?

这是仅在使用 throw new BloxException 时发生的异常 StackTrace:

java.lang.NoClassDefFoundError: fr/eseo/blox/model/BloxException
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2436)
at java.lang.Class.privateGetPublicMethods(Class.java:2556)
at java.lang.Class.getMethods(Class.java:1412)
at org.testng.internal.TestNGClassFinder.<init>(TestNGClassFinder.java:59)
at org.testng.TestRunner.initMethods(TestRunner.java:409)
at org.testng.TestRunner.init(TestRunner.java:235)
at org.testng.TestRunner.init(TestRunner.java:205)
at org.testng.TestRunner.<init>(TestRunner.java:153)
at org.testng.SuiteRunner$DefaultTestRunnerFactory.newTestRunner(SuiteRunner.java:522)
at org.testng.SuiteRunner.init(SuiteRunner.java:157)
at org.testng.SuiteRunner.<init>(SuiteRunner.java:111)
at org.testng.TestNG.createSuiteRunner(TestNG.java:1273)
at org.testng.TestNG.createSuiteRunners(TestNG.java:1260)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1114)
at org.testng.TestNG.run(TestNG.java:1031)
at fr.eseo.ac20.core.validation.runners.Validator.<init>(Validator.java:131)
at fr.eseo.ac20.core.validation.runners.CustomValidator.<init>(CustomValidator.java:21)
at fr.eseo.ac20.core.validation.runners.CustomValidator.main(CustomValidator.java:17)
Caused by: java.lang.ClassNotFoundException: fr.eseo.blox.model.BloxException
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    ... 19 more

作为帮助,我创建了两个简单的测试用例来展示发生了什么,它们可以从examples.zip 下载。解压文件并从命令行切换到 tng_good 文件夹并执行

java -cp testng-6.0.1.jar:. org.testng.TestNG tng.xml

然后切换到 tng_bad 文件夹并执行同样的操作

java -cp testng-6.0.1.jar:. org.testng.TestNG tng.xml

第一个执行,exists 测试失败,第二个给出异常。 (测试方法的代码源在 example 子文件夹中)

【问题讨论】:

  • 这几乎没有意义。无论您是否throw 异常,您都有完全相同的实例创建表达式,无论上下文如何,它的计算结果都完全相同。
  • 向我们展示来自 TestNg 的堆栈跟踪,显示您正在谈论的行为。
  • 我不认为这是异常的特殊之处。您确定类文件在正确的位置,并且在任何需要的地方都输入了正确的名称?
  • Marko,我完全同意你的看法,但是当我尝试抛出一个新的异常时,我得到一个类不存在的异常(来自 TestNg 和我的跑步者类),但是当我刚刚实例化该类,执行我的第一个测试并停止测试(跳过最后一个测试)。
  • 如果他们没有这个类,你希望他们如何运行它?

标签: java unit-testing exception-handling testng


【解决方案1】:

这与例外无关。这里的问题在于您加载代码的方式。

在第一种情况下,您调用

Class.forName(fullClassName);

在一个不可用的类上,你会得到一个ClassNotFoundException,并且这个类不会被加载。

在第二种情况下,TestNG TestRunner 类加载了一个依赖于另一个不可用的类的类。然后稍后它试图获取方法的类型信息......并且由于缺少依赖关系而失败。由于 JVM 现在已告知应用程序缺少依赖项的类,因此它现在处于该类“损坏”的状态。结果,它抛出了一个不同的异常NoClassDefFoundError


基本上,您独立加载和测试类的想法是行不通的。当您加载一个类时,它所依赖的任何类(包括它抛出的任何异常)都需要可用于加载......否则您将获得异常。

他们不应该运行它,但学生作为学生,有时即使他们没有完成该部分,他们也会尝试运行所有测试。

简单。向他们解释,如果他们这样做是行不通的:-)

【讨论】:

  • 我同意你的看法,但我现在通过链接添加了一个示例(参见我编辑的第一篇文章),一个测试按预期执行,Class.forName(...) 正确表示该类不存在,但是当抛出异常时,测试不会执行。
猜你喜欢
  • 1970-01-01
  • 2015-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-04
相关资源
最近更新 更多