文件读取期间强制IOException

时间:2010-04-02 13:03:59

标签: junit

我有一段代码从文件中读取数据。我想在此代码中强制执行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
            }
        }
    }

12 个答案:

答案 0 :(得分:10)

免责声明:我没有在非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();

答案 1 :(得分: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);

答案 2 :(得分:2)

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

答案 3 :(得分:1)

你可以使用像MockitoEasymock (+classpath)这样的Mock库来创建一个Mock文件对象(较新的libs具有类加载器扩展,可以模拟像File这样的具体类),或者可以与{ {3}}并为构造函数调用生成一个mock,并在调用时抛出相应的异常。

答案 4 :(得分:1)

您可以通过在BufferedReader上调用close方法来强制执行异常:

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

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

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

我希望有所帮助。

答案 5 :(得分:1)

在测试中定义一个抛出异常的重载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);
}

答案 6 :(得分:1)

晚了聚会,但是我找到了一种强制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

答案 7 :(得分:0)

你可以为一个太大的文件引发这个异常。

答案 8 :(得分: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中的行为相同。

答案 9 :(得分:0)

例如,您可以使用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:刚刚意识到这个问题是几年前提出的。 :)希望这几天可以帮助别人找到答案。

答案 10 :(得分:0)

您可以从JDK7模拟java.nio.file.FileSystem。我写了http://github.com/dernasherbrezon/mockfs专门用于在测试过程中生成IOException。

答案 11 :(得分:-1)

您可以随时抛出自己的IOException

throw new IOException("Test IOException");