强制 FileNotFoundException

发布于 2024-07-14 20:06:45 字数 345 浏览 9 评论 0原文

我正在为一段代码编写一个测试,其中包含我试图覆盖的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

绅士风度i 2024-07-21 20:06:45

您可以将 cacheFileName 设置为无效名称或您知道不存在的名称。

You could set cacheFileName to an invalid name or to one you know doesn't exist.

无声无音无过去 2024-07-21 20:06:45

从你的评论来看:

是的,我想这个问题应该
真正的问题是“我如何创建一个
两个 Linux 上都不存在的文件
和Windows?”在Windows上,我可以使用
'new File("X:/")',其中 X: 是一个驱动器
不存在的字母。 在 Linux 上,
这不起作用,因为这是一个
有效的文件名。

查看 java.io.File.createTempFile。 使用它来创建文件,然后将其删除。

可能会传递这样的内容:

File tempFile;

tempFile = createTempFile(getClass().getName(), 
                          Long.toString(System.currentTimeMillis());
tempFile.delete();

这应该以平台独立的方式为您提供一个唯一的名称,您可以安全地使用它,而不必(非常)担心它的存在。

From your comment:

Yes, I suppose the question should
really have been "How do I create a
file that does not exist on both Linux
and Windows?" On windows, I can use
'new File("X:/")', where X: is a drive
letter that does not exist. On Linux,
this does not work because that is a
valid file name.

Look at java.io.File.createTempFile. Use it to create the file and then delete it.

Probably pass it something like:

File tempFile;

tempFile = createTempFile(getClass().getName(), 
                          Long.toString(System.currentTimeMillis());
tempFile.delete();

That should give you a unique name in a platform indendent manner that you can safely use without (much) fear of it existing.

江南月 2024-07-21 20:06:45

任何测试都有两个部分:让它发生并衡量您是否获得了正确的结果。

错误注入

最简单的答案就是前面提到的,即将 cacheFileName 设置为一个永远不存在的文件。 在这种情况下,这可能是最实用的答案。

但是,要导致任意条件(例如 IOException),您真正想要的是 故障注入。 这会强制代码中出现错误,而无需强制您检测源代码。 以下是执行此操作的一些方法:

  • 模拟对象 您可以使用工厂方法来创建重写的 ObjectOutputStreamFileOutputStream。 在测试代​​码中,实现会在您想要的时候抛出 IOException,而在生产代码中不会修改正常行为。
  • 依赖注入 为了将模拟对象放在正确的位置,您可以使用诸如 之类的框架SpringSeam 将适当的对象“注入”到正在执行工作的类中。 您可以看到这些框架甚至对将注入的对象具有优先级,因此在单元测试期间您可以使用测试对象覆盖生产对象。
  • 面向方面编程而不是改变代码的结构无论如何,你可以使用AOP将错误注入到正确的位置。 例如,使用 AspectJ 您可以定义一个 切入点,您希望从其中抛出异常,并具有 Advice 抛出所需的异常。

Java 上的故障注入还有其他答案; 例如,一个名为 AProbe 的产品很久以前就开创了 C 语言中的 AOP,而且它们还有一个Java产品。

验证

获取抛出的异常是一个好的开始,但您还必须验证是否获得了正确的结果。 假设您拥有的代码示例是正确的,您想要验证您是否记录了该异常。 上面有人提到为您的记录器使用模拟对象,这是一个可行的选择。 您还可以在此处使用 AOP 来捕获对记录器的调用。

我假设记录器是 log4j; 为了解决类似的问题,我实现了自己的 log4j 附加程序,它捕获 log4j 输出:我专门捕获 ERRORFATAL,它们可能是此类中有趣的日志消息一个案例。 附加程序在 log4j.xml 中引用,并在测试运行期间激活以捕获错误日志输出。 这本质上是一个模拟对象,但我不必重构所有获得 log4j Logger 的代码。

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:

  • Mock objects You could use a factory method to create an overridden ObjectOutputStream or FileOutputStream. In test code the implementation would throw an IOException when you wanted to, and in production code would not modify the normal behavior.
  • Dependency Injection In order to get your Mock Object in the right place you could use a framework such as Spring or Seam to "inject" the appropriate object into the class that's doing the work. You can see that these frameworks even have a priority for objects that will be injected, so that during unit testing you can override the production objects with test objects.
  • Aspect Oriented Programming Instead of changing the structure of your code at all, you can use AOP to inject the fault in the right place. For instance, using AspectJ you could define a Pointcut where you wanted the exception to be thrown from, and have the Advice throw the desired exception.

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 and FATAL, which are likely to be the interesting log messages in such a case. The appender is referenced in log4j.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 log4j Logger.

错爱 2024-07-21 20:06:45

我正在为一段代码编写测试
其中有一个 IOException catch
我试图涵盖的内容。

我不完全确定我理解你的目标,但是如果你想测试是否抛出异常,你可以告诉测试你希望它抛出异常:

@Test(expected=IOException.class)

如果不抛出异常,你的测试将失败,并成功如果它被抛出(例如,如果 cacheFileName 文件不存在)。

I'm writing a test for a piece of code
that has an IOException catch in it
that I'm trying to cover.

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:

@Test(expected=IOException.class)

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).

迷乱花海 2024-07-21 20:06:45

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.

鹤舞 2024-07-21 20:06:45

两种简单的方法是将cacheFileName 设置为不存在的文件或将指定文件设置为只读访问。

-约翰

Two easy ways would be either set cacheFileName to a non-existent file or set the specified file to read-only access.

-John

海夕 2024-07-21 20:06:45

由于当前编写的代码,您可以尝试模拟 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.

生来就爱笑 2024-07-21 20:06:45
cacheFileName = "thisFileShouldNeverExistAndIfItDoesYouAreScrewingUpMyTests";

当然,您可以采取步骤并跳过障碍以编程方式确保文件名永远不会存在,或者您可以使用在 99.99999% 的情况下永远不会存在的字符串。

cacheFileName = "thisFileShouldNeverExistAndIfItDoesYouAreScrewingUpMyTests";

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.

旧话新听 2024-07-21 20:06:45

我希望这就是你的意思。

if(new File(cachedFile).exists()) {
    oos = new ObjectOutputStream(new FileOutputStream(cacheFileName));
    //do your code here
} else {
    throw new FileNotFoundException("File doesn't exist!");
}

I hope this is what you meant.

if(new File(cachedFile).exists()) {
    oos = new ObjectOutputStream(new FileOutputStream(cacheFileName));
    //do your code here
} else {
    throw new FileNotFoundException("File doesn't exist!");
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文