1

我正在为一段代码编写一个测试,其中包含我试图覆盖的 IOException 捕获。try/catch 看起来像这样:

try {
    oos = new ObjectOutputStream(new FileOutputStream(cacheFileName));
} catch (IOException e) {
    LOGGER.error("Bad news!", e);
} finally {

最简单的方法似乎是让 FileOutputStream 抛出 FileNotFoundException,但也许我做错了。

有没有人有任何提示?

4

9 回答 9

5

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

于 2009-03-02T23:13:12.323 回答
4

从您的评论中:

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

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

可能通过它是这样的:

File tempFile;

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

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

于 2009-03-02T23:37:04.403 回答
2

任何测试都有两个部分:让它发生和衡量你得到了正确的结果。

故障注入

最简单的答案是已经提到的那个,即设置cacheFileName为一个永远不会存在的文件。在这种情况下,这可能是最实际的答案。

但是,要导致诸如 的任意条件IOException,您真正想要的是故障注入。这会强制您的代码出现错误,而不会强制您检测源代码。这里有一些方法可以做到这一点:

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

Java 上的故障注入还有其他答案;例如,一个名为AProbe的产品很早以前就开创了 C 语言中可以称为 AOP 的东西,他们也有一个 Java 产品。

验证

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

我假设记录器是log4j;为了解决类似的问题,我实现了自己的 log4j appender,它捕获 log4j 输出:我专门只捕获ERRORand FATAL,在这种情况下,它们很可能是有趣的日志消息。appenderlog4j.xml在测试运行期间被引用并被激活以捕获错误日志输出。这本质上是一个模拟对象,但我不必重组所有得到 log4j 的代码Logger

于 2009-03-03T01:51:53.487 回答
0

我正在为一段代码编写一个测试,其中包含我试图覆盖的 IOException 捕获。

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

@Test(expected=IOException.class)

如果没有抛出异常,您的测试将失败,如果抛出异常(例如,如果cacheFileName文件不存在)则成功。

于 2009-03-02T23:18:10.220 回答
0

FileNotFoundException 显然会触发捕获。javadoc 说明了将被抛出的情况。

您还应该考虑 ObjectOutputStream 构造函数可能会引发 IOException,因此可能希望在您的测试中涵盖这种情况。

于 2009-03-02T23:18:49.737 回答
0

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

-约翰

于 2009-03-02T23:20:40.107 回答
0

由于当前编写的代码,您可以尝试模拟 LOGGER 对象上的 error() 调用,并检查它是否在您期望 IOException 时被调用。

您的测试愿望可能在编写代码时发现了一个根本问题。发生错误,但没有布尔值或标志值(将文件名设置为特殊模式)提供其他代码部分以确定写入文件是否成功。如果它包含在一个函数中,也许你可以返回一个布尔值或设置一个对象级变量。

于 2009-03-02T23:23:01.770 回答
0
cacheFileName = "thisFileShouldNeverExistAndIfItDoesYouAreScrewingUpMyTests";

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

于 2009-03-02T23:40:16.330 回答
0

我希望这就是你的意思。

if(new File(cachedFile).exists()) {
    oos = new ObjectOutputStream(new FileOutputStream(cacheFileName));
    //do your code here
} else {
    throw new FileNotFoundException("File doesn't exist!");
}
于 2012-07-03T05:50:14.047 回答