ファイルからデータを読み取るコードがあります。テスト目的でこのコードに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
}
}
}
免責事項:これは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();
ファイル名ではなく、リーダーを受け入れるようにコードを少しリファクタリングできる場合は、モックを使用できます。 EasyMock を使用すると、モックリーダーを作成し、必要なメソッドのいずれかを呼び出したときに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);
スーパーユーザーとしてファイルを作成してから、標準ユーザーとして読み取ることができます。そこにパーミッションの問題があるはずです。または、Linuxを使用していると仮定してchmodします。非表示/保護されたディレクトリに配置することもできます。
Mockito や Easymock(+ classpath) のようなモックライブラリを使用してモックファイルオブジェクトを作成できます(新しいライブラリには、Fileのような具体的なクラスをモックできるクラスローダー拡張機能があります)。または、 PowerMock(ブログを参照) のようなものと連携して、コンストラクター呼び出し用にモックを生成し、呼び出されたときに適切な例外をスローすることができます。
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
}
それがお役に立てば幸いです。
テストで、例外をスローするオーバーロードされた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);
}
パーティーに遅れましたが、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を出力します
たとえば、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:質問が何年も前に行われたことに気づきました。 :)うまくいけば、最近誰かが答えを見つけるのに役立つでしょう。
ファイルが大きすぎる場合は、この例外を発生させることができます。
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では同じように動作します。
JDK7からJava.nio.file.FileSystem
をモックできます。私は http://github.com/dernasherbrezon/mockfs 特にテスト中にIOExceptionsを生成するために書きました。