JUnit 4 and Suspend-on-Exception

9
当我的代码中抛出未捕获的异常时,我习惯于让调试器停在抛出语句处,以便我可以检查异常抛出时涉及的所有对象的成员和本地变量。使用IntelliJ Idea可以通过转到“运行”,“查看断点” ,选择“异常断点”选项卡,勾选“任何异常”,并确保“已捕获异常”复选框未选中,而“未捕获异常”复选框已选中来实现这一点。对于Eclipse和Visual Studio(用于C#),则有所不同,但大致相同。
具有这种方式调试器的能力非常有用;事实上,它非常有用,以至于我根据此结构化程序的主循环:在发布版本中,主循环当然嵌入在try-catch-all中;但在调试版本中,在主循环中没有try-catch块,因此任何未在程序内部任何位置捕获的异常都将保持未捕获状态,以便调试器会在抛出异常的那一刻暂停我的程序。
然而,在使用JUnit测试我的Java类时,我遇到了一个问题:调试器不会在任何异常上停止。相反,发生的是不仅捕获预期的异常,而且自动地捕获未预期的异常,并给我一个死后异常堆栈跟踪,以尝试理解。这不太好。
我曾经认为这是因为JUnit使用java.lang.reflect.Method.invoke(),该方法捕获所有异常并将它们转换为TargetInvocationExceptions,但然后我编写了自己的自定义JUnit运行器,该运行器了解我的测试类并直接调用其方法而没有Method.invoke(),但问题仍然存在。这意味着问题在核心JUnit中高度存在。
那么,还有其他人遇到同样的问题吗?是否有人知道解决方案,以便我们可以在使用JUnit进行测试时暂停程序执行在未预期的异常上?
相关(未回答)问题:Eclipse Junit测试运行器上未捕获的运行时异常挂起 相关(未回答)问题:如何在jUnit测试用例中中断调试器? 相关(部分回答)问题:在Eclipse中使用jUnit中断异常(被接受的答案说:“如果您在jUnit中调试单个方法,则断点开始工作。如果在jUnit中调试整个类或包,则调试器不起作用。)”

你正在使用哪个版本的JUnit?我可以在我的测试中捕获未捕获的异常,Eclipse Indigo Build 20110615-0604,JUnit 4。 - Perception
2
我正在使用JUnit 4.8.1。请注意,这个问题不是关于捕获未捕获的异常;它是关于在未捕获的异常上使调试器暂停程序执行。换句话说,它是关于让throw指令在抛出未捕获的异常时像断点一样行为的问题。 - Mike Nakis
我想我表达不够清楚。我的IDE(Eclipse Indigo)会自动暂停执行,如果我告诉它,在捕获/未捕获的异常时。即使在运行JUnit 4测试时也是如此。 - Perception
哦,我明白了。那很有趣,我会去查一下并且稍后回复你。 - Mike Nakis
@Perception 我无法确认您的观察结果。不过,我找到了一条新信息并在我的回答末尾添加了它。(运行整个测试套件与运行单个测试。)这是否与您的观察结果相符? - Mike Nakis
2个回答

1
我希望我理解问题正确,如果我错了,请纠正我:
  • 你有一个测试,它抛出了一个异常,但你没有自己捕获它(因此在这个意义上来说,它是未被捕获的)
  • 当你使用JUnit4测试运行器调试这个测试时,JUnit会显示测试失败(因为它抛出了异常)
  • 但线程没有被挂起,这是你想要实现的
  • 即使你已经启用了preferences | java | debug | suspend execution on uncaught exceptions
在这种情况下,我认为这是预期的行为,JUnit捕获并吞噬了你的异常,因此从eclipse的角度来看,它不是未被捕获的,如https://bugs.eclipse.org/bugs/show_bug.cgi?id=414133所述。
你可以通过设置自己的规则来让eclipse在任何情况下都挂起。 Debug perspective | breakpoint view | J! icon | check suspend on caught exception

你对问题的理解是正确的。然而,你提出的解决方案不可行,因为成千上万个异常被抛出(这些异常都被捕获),既包括我无法控制的代码,也包括我的正常操作下的代码,还包括我为了测试错误检查和处理代码而编写的代码。 - Mike Nakis
我甚至无法使用类过滤器来处理Java运行时抛出并被捕获的异常,因为有时Java运行时抛出的异常会传播到我的代码中,我希望调试器能够在我的代码调用引发异常的运行时方法处中断,但是Java调试器似乎没有像Microsoft Visual Studio那样的“仅在我的代码中中断”的概念。 - Mike Nakis
啊,我明白了。鉴于我发布的链接,我猜你最后一句话是正确的,即Eclipse调试器似乎没有暂停只在你的代码中。这似乎只能让JUnit不吞咽你的异常成为你唯一的选择...我不知道那是否可能... - Hirle

0

作为研究测试失败时使用的一种解决方法,您可以在主方法中创建一个有问题的测试类实例,并使用异常断点方法手动调用它的测试方法(顺便说一下,这是非常酷的方法,感谢提出这个问题)。这样,方法就不会通过反射调用。


2
谢谢您的回复,但正如您所说,这不是一个真正的解决方案,而是一种变通方法。事实上,更容易的方法是直接转到抛出异常的行(通过单击堆栈跟踪),在那里放置断点并重新运行。我只是想避免这样做。 - Mike Nakis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接