2012-01-10 2 views
7

私のコードカバレッジを確認している間に、多くのユニットテストでfinallyブロックでInputStreamをクローズしようとしているブロックを確認できませんでした。最終的に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()を使用することを検討してください。 ""の方法は、別のクラスにBufferedInputStreamの作成を外部化し、モックを挿入することです。あなたは適切なclose()メソッドが呼び出されたかどうか確認することができます。 fileSystemFileSystemインタフェースのインスタンスである

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

@JeffFosterの答えは、しかし、私は(多くのコードを犠牲にして)継承上で構図をお勧めします、私が何を意味するかにかなり近いですテストのために生産コードや模擬コードに注入された簡単な実際の実装です。

interface FileSystem { 

    InputStream open(String file); 

} 

ファイルオープンの外部化のもう1つの利点は、バッファリングを削除するか暗号化を追加するかを決める場合、変更する場所が1つだけであることです。

あなたは(Mockitoを使用して)モックを使用してテストコードをインスタンス化し、そのインタフェースを持つ:あなたが嘲笑BufferedInputStreamを注入する必要があり

//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

ありがとうございました。まさに私が探していたものです:) Jeffにも感謝します。 – fyr

5

あなたはこの

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 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 void TestSomething() { 
    InputStream foo = mock(InputStream.class); // mock object 
    TestMe testMe = new TestMe() { 
    @Override 
    public InputStream createStream() { 
      return foo; 
    } 
    } 

    testMe.something(); 

    verify(foo.close()); 
} 

これは価値があるかどうかは別の質問ですか?今では硬くなり

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

0

- や工場でそれを作成する - とモックのclose()メソッドがスローその後、呼び出されましたIOException

さらに、あなたがそこにロジックがない限り、私は上のブロックを上回らないようにします。

0

私は、それが本当にテストの努力に値するものかどうかあなた自身に尋ねる必要があると思います。テスト中毒者の中には、約100%のテストカバレッジを達成しようとするときのリターンが低下する傾向があります。この場合、提案された解決策のいくつかが実際のコードに対して "テスト可能"にするためにの複雑さを追加するように見えます。私は複雑なテストコードを使っても問題ありませんが、実際のコードに複雑さを加えてテスト可能にすることは、私をひどい考え方にしています。

関連する問題