30

我有一段从文件中读取数据的代码。我想在此代码中强制 IOException 用于测试目的(我想检查代码在这种情况下是否引发了正确的自定义异常)。

例如,有什么方法可以创建一个防止被读取的文件?也许处理一些安全检查会有所帮助?

请注意,传递不存在文件的名称无济于事,因为 FileNotFoundException 有一个单独的 catch 子句。

这是一段代码,可以更好地理解这个问题:

    BufferedReader reader = null;
    try {

        reader = new BufferedReader(new FileReader(csvFile));

        String rawLine;
        while ((rawLine = reader.readLine()) != null) {
            // some work is done here
        }

    } catch (FileNotFoundException e) {
        throw new SomeCustomException();
    } catch (IOException e) {
        throw new SomeCustomException();
    } finally {
        // close the input stream
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                // ignore
            }
        }
    }
4

12 回答 12

14

免责声明:我没有在非 Windows 平台上对此进行测试,因此在具有不同文件锁定特性的平台上可能会有不同的结果。

如果您事先锁定文件,则可以在尝试读取文件时触发 IOException:

java.io.IOException: The process cannot access the file because another process has locked a portion of the file

即使您在同一个线程中,这也有效。

这是一些示例代码:

final RandomAccessFile raFile = new RandomAccessFile(csvFile, "rw");
raFile.getChannel().lock();
于 2011-07-25T12:00:03.660 回答
4

如果您可以稍微重构代码以接受 Reader 而不是文件名,则可以使用模拟。使用EasyMock,您可以创建一个模拟 Reader,并将其设置为在调用任何您希望的方法时抛出 IOException。然后你只需将它传递给要测试的方法,然后看看会发生什么:-)

void readFile(Reader reader) throws SomeCustomException {
    try {
        String rawLine;
        while ((rawLine = reader.readLine()) != null) {
            // some work is done here
        }

    } catch (FileNotFoundException e) {
        throw new SomeCustomException();
    } catch (IOException e) {
        throw new SomeCustomException();
    } finally {
        // close the input stream
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                // ignore
            }
        }
    }
}

然后是测试代码:

mockReader = createMock(Reader.class);
expect(mockReader.readLine()).andThrow(
        new IOException("Something terrible happened"));
replay(mockReader);

objectToTest.readFile(reader);
于 2010-04-02T13:07:38.813 回答
3

在您的测试中定义一个引发异常的重载 fileInputStream

FileInputStream s;
try {
    s = new FileInputStream(fileName) {

           @Override
           public int read() throws IOException {
              throw new IOException("Expected as a test");
           }
       };
} catch (FileNotFoundException e) {
   throw new RuntimeException(e.getMessage(), e);
}
于 2016-08-24T13:36:10.093 回答
3

聚会迟到了,但我找到了一种强制 IOException 的方法。我正在使用 BufferedWriter/Reader 保存/读取文本文件,并且正在执行如下所示的测试:

public void testIOException() {
    try {
        int highScore = loadHighScore("/");
        fail("IOException should have been thrown");
    } catch (MissingFileException e) {
        fail("IOException should have been thrown");
    } catch (IOException e) {
        // expected
    }
}

其中“/”是文件名。在 loadHighScore 里面有一行:

BufferedWriter bw = new BufferedWriter(new FileWriter(file));

因为我的测试将“file”输入为“/”,所以它输出了一个 IOException

于 2019-02-19T04:26:38.777 回答
2

您可以通过调用 close 方法来强制异常BufferedReader

    reader = new BufferedReader(new FileReader(csvFile));

    // invoke the Close() method.
    reader.Close();

    String rawLine;
    while ((rawLine = reader.readLine()) != null) {
        // some work is done here
    }

我希望这会有所帮助。

于 2012-10-12T17:40:53.247 回答
2

您可以尝试以超级用户身份创建文件,然后以标准用户身份阅读它。那里应该有权限问题。或者只是假设你在 Linux 上 chmod 。您也可以尝试将其放在隐藏/受保护的目录中。

于 2010-04-02T13:06:37.100 回答
2

java.nio.file.FileSystem您可以从 JDK7模拟。我专门为在测试期间生成 IOExceptions编写了http://github.com/dernasherbrezon/mockfs 。

于 2019-04-23T14:47:57.807 回答
1

您可以使用 Mock 库(如MockitoEasymock (+classpath))来创建 Mock 文件对象(较新的库具有类加载器扩展,可让您模拟 File 等具体类),或者可以与PowerMock 之类的东西合作(参见博客)并拥有一个mock 为构造函数调用生成,并在调用时抛出相应的异常。

于 2010-04-02T21:24:47.230 回答
1

您可以使用例如 Mockito 来模拟它,但是您需要重构您的代码,以便更好地测试它。如果您使用 java 7+,我还建议使用 try-with-resources。你的代码看起来会更干净。

您可以将阅读器创建提取到一个单独的方法中,以便您可以用模拟替换实现。像这样

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class SomeClass {

    public static final String IO_EXCEPTION = "IO Exception";
    private String csvFile ="some_path";

    public void someMethod() {
        BufferedReader reader = null;
        try {
            reader = getReader();
            String rawLine;
            while ((rawLine = reader.readLine()) != null) {
                // some work is done here
            }

        } catch (FileNotFoundException e) {
            throw new SomeCustomException("FNF Exception");
        } catch (IOException e) {
            throw new SomeCustomException(IO_EXCEPTION);
        } finally {
            // close the input stream
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    // ignore
                }
            }
        }
    }

    BufferedReader getReader() throws FileNotFoundException {
        return new BufferedReader(new FileReader(csvFile));
    }

    class SomeCustomException extends RuntimeException {

        public SomeCustomException(String message) {
            super(message);
        }
    }
}

测试将如下所示

    import static org.assertj.core.api.Assertions.assertThatThrownBy;

import SomeCustomException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;

@RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {

    @Mock
    private BufferedReader bufferedReader;

    @Test
    public void testMethod() throws IOException {
        Mockito.when(bufferedReader.readLine()).thenThrow(new IOException());

        SomeClass someClass = new SomeClass() {
            @Override
            BufferedReader getReader() throws FileNotFoundException {
                return bufferedReader;
            }
        };
        assertThatThrownBy(() -> someClass.someMethod()).isInstanceOf(SomeCustomException.class)
                                                        .hasMessage(SomeClass.IO_EXCEPTION);
    }
}

如果您使用 try-with-resource,这就是您的 someMethod 的样子

public void someMethod() {
    try(BufferedReader reader = getReader()) {
        String rawLine;
        while ((rawLine = reader.readLine()) != null) {
            // some work is done here
        }

    } catch (FileNotFoundException e) {
        throw new SomeCustomException("FNF Exception");
    } catch (IOException e) {
        throw new SomeCustomException(IO_EXCEPTION);
    }
}

缩短 2 倍 可读性提高 20 倍

PS 作为测试的另一个选项,您可以在测试类中扩展您的 SomeClass 并在测试类中覆盖 someMethod 而不是创建一致的实现。但我更喜欢第一个选项。不过,这是一个品味问题。

希望有帮助。

PPS:刚刚意识到这个问题是几年前提出的。:) 希望这几天它可以帮助某人找到答案。

于 2018-06-23T12:57:32.083 回答
0

您可以针对太大的文件引发此异常。

于 2010-04-02T13:06:12.663 回答
0

我建议不要使用 FileNotFoundException。如果你想为不存在的文件抛出一个特定的异常,我会检查 csvFile.exists()。

例如,您可以将csvFile 设为目录。我测试了你的代码,它抛出了:

File file = new File("actually_a_directory.csv"); file.mkdir(); yourCode(file); // throws FileNotFoundException: "actually_a_directory.csv (Access is denied)"

在我看来,实际上是目录的文件与 FileNotFound 不同,但它在 java 中的作用相同。

于 2016-08-18T22:19:24.753 回答
-2

你总是可以扔你自己的IOException

throw new IOException("Test IOException");
于 2010-04-02T13:05:23.210 回答