我有一段代码从文件中读取数据。我想在此代码中强制执行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
}
}
}
答案 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)
你可以使用像Mockito或Easymock (+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");