在文件读取期间强制 IOException

发布于 2024-08-28 00:47:16 字数 862 浏览 7 评论 0原文

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

I have a piece of code that reads data from a file. I want to force IOException in this code for testing purposes (I want to check if the code throws a correct custom exception in this case).

Is there any way to create a file which is protected from being read, for example? Maybe dealing with some security checks can help?

Please, note that passing the name of a non-existent file cannot help, because FileNotFoundException has a separate catch clause.

Here is the piece of code for better understanding of the question:

    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
            }
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(12

菊凝晚露 2024-09-04 00:47:16

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

Disclaimer: I have not tested this on a non-Windows platform, so it may have different results on a platform with different file locking characteristics.

If you lock the file beforehand, you can trigger an IOException when something attempts to read from it:

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

This works even if you are in the same thread.

Here's some sample code:

final RandomAccessFile raFile = new RandomAccessFile(csvFile, "rw");
raFile.getChannel().lock();
心凉 2024-09-04 00:47:16

如果您可以稍微重构代码以接受 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);

If you can refactor the code slightly to accept a Reader, rather than a filename, you can use mocks. With EasyMock you can create a mock Reader, and set it to throw IOException upon calling any of its methods you wish. Then you just pass it to the method to be tested, and watch what happens :-)

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
            }
        }
    }
}

then the test code:

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

objectToTest.readFile(reader);
我是有多爱你 2024-09-04 00:47:16

您可以通过在 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
    }

我希望这会有所帮助。

You could force an exception by invoking the close method on your 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
    }

I hope that helps.

无语# 2024-09-04 00:47:16

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

Define in your test an overloaded fileInputStream that throws an exception

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);
}
忘东忘西忘不掉你 2024-09-04 00:47:16

虽然迟到了,但我找到了一种强制 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));

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

Late to the party, but I found a way to force an IOException. I am saving/reading a text file using BufferedWriter/Reader and am doing a test that looks like this:

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
    }
}

Where "/" is the filename. Inside loadHighScore there's the line:

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

Because my test inputs "file" as "/", it outputs an IOException

我的影子我的梦 2024-09-04 00:47:16

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

You could try creating the file as a superuser and then reading it as a standard user. There should be permissions issues there. Or just chmod the thing assuming you're on Linux. You can also try putting it in a hidden / protected directory.

同展鸳鸯锦 2024-09-04 00:47:16

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

You can mock java.nio.file.FileSystem from JDK7. I wrote http://github.com/dernasherbrezon/mockfs specifically for generating IOExceptions during the test.

战皆罪 2024-09-04 00:47:16

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

You can use a Mock library like Mockito or Easymock (+classpath) to create a Mock file object (newer libs have classloader extensions that let you mock concrete classes like File), or can cooperate with something like PowerMock (see blog) and have a mock generated for the constructor call, and throw the appropriate exception when called.

A君 2024-09-04 00:47:16

您可以使用 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);
    }
}

的 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);
    }
}

所示 如果您使用 try-with-resource短 2 倍、可读性高 20 倍

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

希望有帮助。

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

You can use for example Mockito to emulate that, however you would need to refactor your code so it were better testable. I would also advise to use try-with-resources if you use java 7+. Your code will look much cleaner.

You might extract the reader creation to a separate method so you could then replace an implementation with a mock. Like this

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);
        }
    }
}

The test would look as following

    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);
    }
}

This is how your someMethod might look like if you use try-with-resource

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 times shorter 20 times more readable

PS as another option for the test, you might extend your SomeClass in the test class and override someMethod in the test class instead of creating an unanimous implementation. But I like the first option more. It is a matter of taste though.

Hope that helps.

PPS: Just realized the question was asked years ago. :) Hopefully it helps somebody to find an answer these days.

苏别ゝ 2024-09-04 00:47:16

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

You could make this exception raise for a file that's too large.

染墨丶若流云 2024-09-04 00:47:16

我建议不要使用 FileNotFoundException。如果您想针对不存在的文件引发特定异常,我会检查 csvFile.exists()。

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


文件 file = new File("actually_a_directory.csv");
文件.mkdir();
你的代码(文件); // throws FileNotFoundException: "actually_a_directory.csv (Access is returned)"

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

I would recommend against using the FileNotFoundException. If you want to throw a specific exception for the file not existing, I would check csvFile.exists().

For example, you can make csvFile a directory. I tested your code and it threw:


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

In my opinion, a file actually being a directory is not the same as FileNotFound, yet it acts the same in java.

纵山崖 2024-09-04 00:47:16

您始终可以抛出自己的 IOException:

throw new IOException("Test IOException");

You can always throw your own IOException:

throw new IOException("Test IOException");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文