2012-01-10 4 views
7

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

Один пример отрывок:

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

Есть ли соответствующее решение проверить все внутри, наконец, блок с помощью JUnit4?

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

ответ

6

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

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

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

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

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

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

interface FileSystem { 

    InputStream open(String file); 

} 

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

Имея этот интерфейс инстанцировании тестовый код с издевается (с использованием 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(); 
+0

Согласен. Я нахожу вариант просто переопределить метод в тесте очень полезным, но часто это промежуточный шаг на пути выбора композиции. C# является PITA в этом отношении, поскольку методы по умолчанию не являются виртуальными, поэтому я нахожу, что мне часто приходится прыгать целиком (что раздражает, поскольку вы хотите работать с минимальными возможными изменениями). –

+0

Спасибо, что это именно то, что я искал :) Спасибо также Джеффу – fyr

5

Вы можете отрефакторить код немного

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

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

Кроме того, я не буду, чтобы блок finally выше, пока у вас нет никакой логики.

0

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