2012-01-10 45 views
7

Trong khi xem xét phạm vi mã của tôi, tôi nhận thấy rất nhiều bài kiểm tra Đơn vị không kiểm tra các khối cuối cùng cố gắng đóng InputStreams mở trong các khối cuối cùng.Kiểm tra đơn vị cuối cùng chặn trong Java 6

Một Ví dụ đoạn trích là:

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

Có bất kỳ giải pháp thích hợp để kiểm tra tất cả mọi thứ bên trong khối finally sử dụng Junit4?

Tôi biết rằng mức độ bao phủ mã 100% không đạt được trong khi vẫn giữ được hiệu suất tối đa. Tuy nhiên, những đường màu đỏ này là một loại kính mắt trong báo cáo.

Trả lời

6

Trước hết xem xét sử dụng IOUtils.closeQuietly(), mà sẽ giảm mã chưa được kiểm tra của bạn (và có lẽ sự trùng lặp) vào:

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

Bây giờ nó trở nên khó khăn. Cách "phải" sẽ là để bên ngoài việc tạo ra BufferedInputStream vào một lớp khác và tiêm mô phỏng. Có một mô hình, bạn có thể xác minh xem phương thức close() có được yêu cầu hay không.

@JeffFoster 's câu trả lời là khá gần với những gì tôi muốn nói, tuy nhiên tôi muốn giới thiệu thành phần trên thừa kế (tại các chi phí của mã trở lên):

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

đâu fileSystem là một thể hiện của giao diện FileSystem với việc triển khai thực sự đơn giản được chèn vào mã sản xuất hoặc giả lập để thử nghiệm.

interface FileSystem { 

    InputStream open(String file); 

} 

Lợi ích khác của việc mở rộng mở tệp là nếu bạn quyết định xóa bộ đệm hoặc thêm mã hóa, chỉ có một nơi để sửa đổi.

Có giao diện mà bạn nhanh chóng mã kiểm tra của bạn với mocks (sử dụng 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

Tôi đồng ý. Tôi thấy tùy chọn chỉ ghi đè một phương pháp trong một bài kiểm tra rất hữu ích, nhưng nó thường là một bước trung gian trên con đường để chọn bố cục. C# là một PITA ở khía cạnh đó vì các phương thức không phải là ảo theo mặc định vì vậy tôi thấy tôi thường phải nhảy toàn bộ con đường (điều này gây phiền nhiễu khi bạn muốn làm việc với những thay đổi nhỏ nhất có thể). –

+0

Cảm ơn đó là chính xác những gì tôi đang tìm kiếm :) Cảm ơn Jeff – fyr

5

Bạn có thể cấu trúc lại mã một chút

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

Để một cái gì đó như thế này

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

Và bây giờ bạn có thể viết bài kiểm tra của bạn để nắm bắt những lớp input stream và xác minh rằng được đóng lại. (mã là thô, nhưng hy vọng bạn sẽ có được ý tưởng chung).

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

Liệu điều này có đáng hay không là một câu hỏi khác!

0

Bạn nên tiêm một chế giễu BufferedInputStream - hoặc tạo ra nó với một nhà máy - và khi phương pháp của mock close() được gọi sau đó ném an IOException.

Ngoài ra, tôi sẽ không chặn cuối cùng ở trên cho đến khi bạn không có bất kỳ logic nào trong đó.

0

Tôi nghĩ bạn cần phải tự hỏi xem liệu đó có thực sự đáng để thử nghiệm hay không. Một số thử nghiệm những người nghiện rượu có xu hướng bỏ lỡ lợi nhuận giảm dần của cố gắng để đạt được ~ 100% thử nghiệm bảo hiểm.Trong trường hợp này, có vẻ như một số giải pháp được đề xuất thêm nhiều hơn sự phức tạp vào mã thực tế để làm cho nó "có thể kiểm chứng". Tôi ổn với mã thử nghiệm phức tạp, nhưng việc thêm độ phức tạp vào mã thực sự chỉ để làm cho nó "có thể kiểm chứng" tấn công tôi như một ý tưởng khủng khiếp.