Byteman JUnit Runner - 无法在自动关闭的 InputStream#close 上触发 IOException
Posted
技术标签:
【中文标题】Byteman JUnit Runner - 无法在自动关闭的 InputStream#close 上触发 IOException【英文标题】:Byteman JUnit Runner - impossible to trigger IOException on auto-closed InputStream#close 【发布时间】:2014-11-13 03:29:43 【问题描述】:我有以下代码:
Collection<String> errors = ...;
try (InputStream stream = My.class.getResourceAsStream(resource))
// do stuff
catch(IOException ex)
errors.add("Fail");
我正在尝试使用 Byteman Junit Runner 在我提供的(有效)输入流应该被关闭时触发 IOException:
@RunWith(BMUnitRunner.class)
public class MyTest
private My my = new My();
@BMRule(
name = "force_read_error",
targetClass = "java.io.InputStream",
targetMethod = "close()",
action = "throw new IOException(\"bazinga\")"
)
@Test
public void catches_read_error() throws IOException
Collection<String> errors = my.foo("/valid-resource-in-classpath");
assertThat(errors).containsExactly("Fail");
我的测试失败:errors 始终为空,这意味着 Byteman 规则显然没有被执行(代理很好地加载了它,所以我不明白发生了什么)。
如何在通过 try-with-resources 调用的 close 方法上触发 IOException?
【问题讨论】:
【参考方案1】:您的规则没有触发,因为调用时收到的流对象的类
InputStream stream = My.class.getResourceAsStream(resource)
不是“java.io.InputStream”类。它是一个扩展“java.io.InputStream”的类,很可能是“BufferedInputStream”。
要告诉 byteman“为任何扩展 java.io.InputStream 的类触发规则”,你需要在类名前加一个 '^':
targetClass = "^java.io.InputStream"
此更改可能会产生不希望的副作用,即当扩展“java.io.InputStream”的其他对象关闭时也会触发该规则。为了防止这种情况发生,应该在规则中添加一个条件,仅当调用者匹配“My”类的“foo”方法时才会触发。 Byteman 有一个名为“callerMatches”的辅助方法 (Please see also the advanced tutorial)
您的案例的工作条件是:
condition = "callerMatches(\".+My.foo\",true,true)"
作为 BMRule 注释的完整 Byteman 规则定义应如下所示:
@BMRule(
name = "force_read_error",
targetClass = "^java.io.InputStream",
targetMethod = "close()",
condition = "callerMatches(\".+My.foo\",true,true)",
action = "throw new java.io.IOException(\"bazinga\")"
)
【讨论】:
以上是关于Byteman JUnit Runner - 无法在自动关闭的 InputStream#close 上触发 IOException的主要内容,如果未能解决你的问题,请参考以下文章
Junit 的 @RunWith():Runner,即Junit的运行器
Junit 的 @RunWith():Runner,即Junit的运行器
java.lang.NoClassDefFoundError: org/junit/runner/manipulation/Filter
idea com.intellij.junit4.JUnit4TestRunnerUtil$5 overrides final method getRunner.()Lorg/junit/runner
idea com.intellij.junit4.JUnit4TestRunnerUtil$5 overrides final method getRunner.()Lorg/junit/runner