Модульное тестирование наконец блокирует в Java 6 - PullRequest
7 голосов
/ 10 января 2012

При просмотре покрытия кода я заметил, что во многих модульных тестах не проверяются блоки finally, которые пытаются закрыть открытые InputStreams в блоках finally.

Один из примеров:

  try {
      f = new BufferedInputStream(new FileInputStream(source));
      f.read(buffer);
  } finally {
      if (f != null)
          try {
              f.close();
          } catch (IOException ignored) {
          }
      }
  }

Есть ли какое-либо подходящее решение для проверки всего внутри блока finally с использованием JUnit4?

Я знаю, что охват кода 100% недостижим при сохранении максимальной производительности.Тем не менее, эти красные линии являются своего рода притягательным взглядом в отчете.

Ответы [ 4 ]

6 голосов
/ 10 января 2012

Прежде всего рассмотрите возможность использования IOUtils.closeQuietly(), что уменьшит ваш непроверенный код (и, возможно, дублирование) до:

  try {
      f = new BufferedInputStream(new FileInputStream(source));
      f.read(buffer);
  } finally {
      IOUtils.closeQuietly(f);
  }

Теперь это становится сложным.Путь " right " состоит в том, чтобы вывести BufferedInputStream в другой класс и внедрить макет.Имея макет, вы можете проверить, был ли вызван соответствующий метод close(). Ответ

@ JeffFoster довольно близок к тому, что я имею в виду, однако я бы порекомендовал состав вместо наследования (наза счет дополнительного кода):

  try {
      f = fileSystem.open(source);
      f.read(buffer);
  } finally {
      IOUtils.closeQuietly(f);
  }

Где fileSystem - это экземпляр интерфейса FileSystem с простой реальной реализацией, внедренной в производственный код или макет для тестирования.

interface FileSystem {

    InputStream open(String file);

}

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

Имея этот интерфейс, вы создаете свой тестовый код с помощью mock (используя Mockito):

//given
FileSystem fileSystemMock = mock(FileSystem.class);
InputStream streamMock = mock(InputStream.class);

given(fileSystemMock.open("file.txt")).willReturn(streamMock);

//when
//your code

//then
verify(streamMock).close();
5 голосов
/ 10 января 2012

Вы можете немного изменить код

public class TestMe {
  public void doSomething() {
    try {
      f = new BufferedInputStream(new FileInputStream(source));
      f.read(buffer);
    } finally {
      if (f != null)
      try {
          f.close();
      } catch (IOException ignored) { }
    }
  }
}

На что-то вроде этого

public class TestMe {
  public void doSomething() {
    try {
      f = createStream()
      f.read(buffer);
    } finally {
      if (f != null)
      try {
          f.close();
      } catch (IOException ignored) { }
    }
  }

  public InputStream createStream() {
      return new BufferedInputStream(new FileInputStream(source));
  }
}

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

public void TestSomething () {
   InputStream foo = mock(InputStream.class); // mock object
   TestMe testMe = new TestMe() {
     @Override
     public InputStream createStream() {
          return foo;
     } 
   }

   testMe.something();

   verify(foo.close());
}

Стоит ли это того или нет, это другой вопрос!

0 голосов
/ 10 января 2012

Я думаю, вам нужно спросить себя, действительно ли это стоит испытаний. Некоторые тестирующие наркоманы, как правило, пропускают убывающую отдачу, пытаясь достичь ~ 100% тестового покрытия. В этом случае, похоже, что некоторые из предложенных решений добавляют больше сложности к реальному коду, чтобы сделать его «тестируемым». Я в порядке со сложным тестовым кодом, но добавление сложности к реальному коду только для того, чтобы сделать его "тестируемым", кажется мне ужасной идеей.

0 голосов
/ 10 января 2012

Вы должны внедрить смоделированный BufferedInputStream - или создать его с фабрикой - и когда вызывается метод макета close(), тогда выведите IOException.

.наконец, блок выше, пока у вас не будет никакой логики там.

...