强制 FileNotFoundException
我正在为一段代码编写一个测试,其中包含我试图覆盖的 IOException 捕获。 try/catch 看起来像这样:
try {
oos = new ObjectOutputStream(new FileOutputStream(cacheFileName));
} catch (IOException e) {
LOGGER.error("Bad news!", e);
} finally {
最简单的方法似乎是让 FileOutputStream 抛出 FileNotFoundException,但也许我正在以错误的方式处理这一切。
那里有人有任何提示吗?
I'm writing a test for a piece of code that has an IOException catch in it that I'm trying to cover. The try/catch looks something like this:
try {
oos = new ObjectOutputStream(new FileOutputStream(cacheFileName));
} catch (IOException e) {
LOGGER.error("Bad news!", e);
} finally {
The easiest way seems to make FileOutputStream throw a FileNotFoundException, but perhaps I'm going about this all the wrong way.
Anyone out there have any tips?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
您可以将
cacheFileName
设置为无效名称或您知道不存在的名称。You could set
cacheFileName
to an invalid name or to one you know doesn't exist.从你的评论来看:
查看 java.io.File.createTempFile。 使用它来创建文件,然后将其删除。
可能会传递这样的内容:
这应该以平台独立的方式为您提供一个唯一的名称,您可以安全地使用它,而不必(非常)担心它的存在。
From your comment:
Look at java.io.File.createTempFile. Use it to create the file and then delete it.
Probably pass it something like:
That should give you a unique name in a platform indendent manner that you can safely use without (much) fear of it existing.
任何测试都有两个部分:让它发生并衡量您是否获得了正确的结果。
错误注入
最简单的答案就是前面提到的,即将
cacheFileName
设置为一个永远不存在的文件。 在这种情况下,这可能是最实用的答案。但是,要导致任意条件(例如
IOException
),您真正想要的是 故障注入。 这会强制代码中出现错误,而无需强制您检测源代码。 以下是执行此操作的一些方法:ObjectOutputStream
或FileOutputStream
。 在测试代码中,实现会在您想要的时候抛出IOException
,而在生产代码中不会修改正常行为。Java 上的故障注入还有其他答案; 例如,一个名为 AProbe 的产品很久以前就开创了 C 语言中的 AOP,而且它们还有一个Java产品。
验证
获取抛出的异常是一个好的开始,但您还必须验证是否获得了正确的结果。 假设您拥有的代码示例是正确的,您想要验证您是否记录了该异常。 上面有人提到为您的记录器使用模拟对象,这是一个可行的选择。 您还可以在此处使用 AOP 来捕获对记录器的调用。
我假设记录器是 log4j; 为了解决类似的问题,我实现了自己的 log4j 附加程序,它捕获 log4j 输出:我专门捕获
ERROR
和FATAL
,它们可能是此类中有趣的日志消息一个案例。 附加程序在log4j.xml
中引用,并在测试运行期间激活以捕获错误日志输出。 这本质上是一个模拟对象,但我不必重构所有获得 log4jLogger
的代码。There are two parts to any test: getting it to happen and measuring that you got the correct result.
Fault Injection
The easiest answer is the one that's already been mentioned, which is to set
cacheFileName
to a file that will never exist. This is likely the most practical answer in this situation.However, to cause an arbitrary condition such as an
IOException
, what you really want is Fault Injection. This forces faults in your code without forcing you to instrument your source code. Here are a few methods for doing this:ObjectOutputStream
orFileOutputStream
. In test code the implementation would throw anIOException
when you wanted to, and in production code would not modify the normal behavior.There are other answers to fault injection on Java; for instance a product called AProbe pioneered what could be called AOP in C long ago, and they also have a Java product.
Validation
Getting the exception thrown is a good start, but you also have to validate that you got the right result. Assuming that the code sample you have there is correct, you want to validate that you logged that exception. Someone above mentioned using a Mock object for your logger, which is a viable option. You can also use AOP here to catch the call to the logger.
I assume that the logger is log4j; to solve a similar problem, I implemented my own log4j appender which captures log4j output: I specifically capture only
ERROR
andFATAL
, which are likely to be the interesting log messages in such a case. The appender is referenced inlog4j.xml
and is activated during the test run to capture error log output. This is essentially a mock object, but I didn't have to restructure all my code that got a log4jLogger
.我不完全确定我理解你的目标,但是如果你想测试是否抛出异常,你可以告诉测试你希望它抛出异常:
如果不抛出异常,你的测试将失败,并成功如果它被抛出(例如,如果
cacheFileName
文件不存在)。I'm not entirely sure I understand your goal, but if you want to test if the exception is thrown, you can tell the test you expect it to throw the exception:
Your test will then fail if the exception is not thrown, and succeed if it is thrown (like, if the
cacheFileName
file does not exist).FileNotFoundException 显然会触发捕获。 javadoc 说明了将抛出该异常的情况。
您还应该考虑到 ObjectOutputStream 构造函数可能会抛出 IOException,因此可能希望在测试中涵盖这种情况。
A FileNotFoundException would obviously trigger the catch. The javadoc states the cases where it will be thrown.
You should also consider that the ObjectOutputStream constructor can throw an IOException so may want to cover this case in your tests.
两种简单的方法是将cacheFileName 设置为不存在的文件或将指定文件设置为只读访问。
-约翰
Two easy ways would be either set cacheFileName to a non-existent file or set the specified file to read-only access.
-John
由于当前编写的代码,您可以尝试模拟 LOGGER 对象上的 error() 调用,并检查当您期望 IOException 时是否会调用它。
您的测试愿望可能会发现代码编写时的根本问题。 发生错误,但没有布尔值或标志值(将文件名设置为特殊模式)提供其他代码部分来确定写入文件是否成功。 如果它包含在函数中,也许您可以返回布尔值或设置对象级变量。
As the code is currently written, you could try to mock out the error() call on the LOGGER object and check to see if it gets called when you expect an IOException.
Your desire to test may have uncovered a fundamental problem with the code as it's written. An error is occurring but there's no boolean or flag value (set the filename to a special pattern) that provides other sections of code to determine if writing to the file was successful. If this is contained in a function, maybe you could return a boolean or set an object level variable.
当然,您可以采取步骤并跳过障碍以编程方式确保文件名永远不会存在,或者您可以使用在 99.99999% 的情况下永远不会存在的字符串。
Sure you could take steps and jump thru hoops to programatically make sure that the file name will never, ever, ever exist, or you could use a String that will never exist in 99.99999% of cases.
我希望这就是你的意思。
I hope this is what you meant.