Подтвердить что ты не робот

Mocking Files в Java - Mock Contents - Mockito

Я новичок в насмешках, и я пытаюсь высмеять фактическое содержимое (по существу, создаю виртуальный файл только в памяти), чтобы никакие данные не записывались на диск в любой момент.

Я пробовал решения, такие как издевательство над файлом и издевательство над многими из свойств, которые я могу определить как можно больше, а затем писать в него с помощью файла-сценариста/буферизатора, но это не работает, поскольку им нужны канонические пути. Кто-нибудь нашел решение, отличное от этого или подобного, но что я приближаюсь к этому неправильно?

Я делал это так:

private void mocking(){
    File badHTML = mock(File.class);
    //setting the properties of badHTML
    when(badHTML.canExecute()).thenReturn(Boolean.FALSE);
    when(badHTML.canRead()).thenReturn(Boolean.TRUE);
    when(badHTML.canWrite()).thenReturn(Boolean.TRUE);
    when(badHTML.compareTo(badHTML)).thenReturn(Integer.SIZE);
    when(badHTML.delete()).thenReturn(Boolean.FALSE);
    when(badHTML.getFreeSpace()).thenReturn(0l);
    when(badHTML.getName()).thenReturn("bad.html");
    when(badHTML.getParent()).thenReturn(null);
    when(badHTML.getPath()).thenReturn("bad.html");
    when(badHTML.getParentFile()).thenReturn(null);
    when(badHTML.getTotalSpace()).thenReturn(0l);
    when(badHTML.isAbsolute()).thenReturn(Boolean.FALSE);
    when(badHTML.isDirectory()).thenReturn(Boolean.FALSE);
    when(badHTML.isFile()).thenReturn(Boolean.TRUE);
    when(badHTML.isHidden()).thenReturn(Boolean.FALSE);
    when(badHTML.lastModified()).thenReturn(System.currentTimeMillis());
    when(badHTML.mkdir()).thenReturn(Boolean.FALSE);
    when(badHTML.mkdirs()).thenReturn(Boolean.FALSE);
    when(badHTML.setReadOnly()).thenReturn(Boolean.FALSE);
    when(badHTML.setExecutable(true)).thenReturn(Boolean.FALSE);
    when(badHTML.setExecutable(false)).thenReturn(Boolean.TRUE);
    when(badHTML.setReadOnly()).thenReturn(Boolean.FALSE);

    try {
        BufferedWriter bw = new BufferedWriter(new FileWriter(badHTML));
        /*
          badHTMLText is a string with the contents i want to put into the file, 
          can be just about whatever you want
         */
        bw.append(badHTMLText);
        bw.close();

    } catch (IOException ex) {
        System.err.println(ex);
    }
}

Любые идеи или рекомендации будут очень полезны. Где-то после этого я в основном пытаюсь читать из файла с помощью другого класса. Я попытался бы издеваться над каким-то входным потоком, но другой класс не принимает входной поток, так как это класс обработки io для проекта.

4b9b3361

Ответ 1

Вы, кажется, следуете за противоречивыми целями. С одной стороны, вы пытаетесь избежать записи данных на диск, что не является плохой целью в тестах. С другой стороны, вы пытаетесь проверить свой класс обработки ввода-вывода, что означает, что вы будете работать с системными утилитами, которые предполагают, что ваш File будет работать с собственными вызовами. Таким образом, здесь мое руководство:

  • Не пытайтесь издеваться над File. Только не надо. От него зависит слишком много родных вещей.
  • Если вы можете, разделите код обработки ввода-вывода на половину, который откроет File и превратит его в Reader, а половину, которая анализирует HTML из Reader.
  • В этот момент вам вообще не нужен макет - просто создайте StringReader для имитации источника данных.
  • В то время как эта процедура отлично справляется с вашими модульными тестами, вы также можете написать тест интеграции, который использует временный файл и убедиться, что он правильно читает. (Спасибо Brice за то, что добавил этот совет!)

Не бойтесь реорганизовать свой класс, чтобы упростить тестирование, как здесь:

class YourClass {
  public int method(File file) {
    // do everything here, which is why it requires a mock
  }   
}   

class YourRefactoredClass {
  public int method(File file) {
    return methodForTest(file.getName(), file.isFile(),
        file.isAbsolute(), new FileReader(file));
  }   

  /** For testing only. */
  int methodForTest(
      String name, boolean isFile, boolean isAbsolute, Reader fileContents) {
    // actually do the calculation here
  }   
}   

class YourTest {
  @Test public int methodShouldParseBadHtml() {
    YourRefactoredClass yrc = new YourRefactoredClass();
    assertEquals(42, yrc.methodForTest(
        "bad.html", true, false, new StringReader(badHTMLText));
  }   
}   

В этот момент логика в method настолько проста, что не стоит тестировать, и логика в methodForTest настолько проста в доступе, что вы можете протестировать ее в значительной степени.

Ответ 2

Один способ издеваться над вызовами ввода/вывода (с Java 7 это был бы последний класс NIO java.nio.file.Files), чтобы обернуть необходимые вызовы в вашем собственном классе и высмеять его:

public class FileHelper {

    public Path createDirectory(String directoryName) throws IOException {
        return Files.createDirectory(Paths.get(directoryName));
    }

    public boolean exists(String name) throws IOException {
        return Files.exists(Paths.get(name), LinkOption.NOFOLLOW_LINKS);
    }

}

Бизнес-логика находится в ImageManager:

FileHelper fileHelperMock = Mockito.mock(new FileHelper());
ImageManager imageManager = new ImageManagerImpl(fileHelperMock);

Тест проверяет вызов createDirectory() на ваш макет:

imageManager.save("directory");
Mockito.verify(fileHelperMock).createDirectory("directory");

Я бы использовал этот метод во время тестовой разработки, где я не хочу загрязнять тестирование с помощью реального управления файлами (например, удалять созданные каталоги/файлы в блоке finally в каждом модульном тесте).

Тогда у меня были бы приемочные тесты, охватывающие каждый прецедент с реальной обработкой файлов.