Принуждение IOException во время чтения файла

У меня есть фрагмент кода, который считывает данные из файла. Я хочу заставить 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
            }
        }
    }

Ответы

Ответ 1

Отказ от ответственности: я не тестировал это на платформе, отличной от 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();

Ответ 2

Если вы можете реорганизовать код немного, чтобы принять Reader, а не имя файла, вы можете использовать mocks. С помощью EasyMock вы можете создать mock 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);

Ответ 3

Вы можете попробовать создать файл в качестве суперпользователя, а затем прочитать его как стандартного пользователя. Там должны быть проблемы с разрешениями. Или просто chmod, предполагая, что вы работаете в Linux. Вы также можете попробовать поместить его в скрытый/защищенный каталог.

Ответ 5

Вы можете вызвать исключение, вызвав метод 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
    }

Я надеюсь, что это поможет.

Ответ 6

Вы можете сделать это повышение для слишком большого файла.

Ответ 7

Я бы рекомендовал не использовать 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.

Ответ 8

Определите в своем тесте перегруженный файлInputStream, который генерирует исключение

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

Ответ 9

Вы можете использовать, например, Mockito, чтобы подражать этому, однако вам нужно будет реорганизовать ваш код, чтобы он был лучше проверен. Я бы посоветовал использовать try-with-resources, если вы используете java 7+. Ваш код будет выглядеть намного чище.

Вы можете извлечь создание читателя в отдельный метод, чтобы затем заменить реализацию макетом. Как это

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, если вы используете 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 раза короче в 20 раз более читаемых

PS как еще один вариант теста, вы можете расширить свой SomeClass в тестовом классе и переопределить someMethod в тестовом классе вместо создания единодушной реализации. Но мне больше нравится первый вариант. Однако это вопрос вкуса.

Надеюсь, это поможет.

PPS: Просто понял, вопрос задавался много лет назад. :) Надеюсь, это помогает кому-то найти ответ в эти дни.

Ответ 10

Вы всегда можете создать свой собственный IOException:

throw new IOException("Test IOException");