2008-09-29 26 views
8

Làm thế nào để mọi người tiếp cận chế nhạo TcpClient (hoặc những thứ như TcpClient)?TDD và Mocking out TcpClient

Tôi có một dịch vụ có trong TcpClient. Tôi có nên quấn cái đó vào cái gì đó khác nhạo báng không? Làm thế nào tôi nên tiếp cận điều này?

Trả lời

22

Khi đến các lớp mô phỏng không thân thiện với thử nghiệm (ví dụ: niêm phong/không triển khai bất kỳ giao diện/phương thức nào không phải ảo), bạn có thể muốn sử dụng mẫu thiết kế Adapter.

Trong mẫu này, bạn thêm lớp bao bì thực hiện giao diện. Sau đó, bạn nên giả lập giao diện và đảm bảo tất cả mã của bạn sử dụng giao diện đó thay vì lớp bê tông không thân thiện. Nó sẽ trông giống như thế này:

public interface ITcpClient 
{ 
    Stream GetStream(); 
    // Anything you need here  
} 
public class TcpClientAdapter: ITcpClient 
{ 
    private TcpClient wrappedClient; 
    public TcpClientAdapter(TcpClient client) 
    { 
    wrappedClient = client; 
    } 

    public Stream GetStream() 
    { 
    return wrappedClient.GetStream(); 
    } 
} 
+0

Điều này thật hoàn hảo! Cảm ơn! –

+0

+1 giải thích tốt nhất cùng với ví dụ đơn giản tốt đẹp – Ahmad

+0

cảm ơn @funkymushroom, cố định –

2

Sử dụng mẫu Adaptor chắc chắn là cách tiếp cận TDD chuẩn cho vấn đề. Bạn có thể, tuy nhiên, cũng chỉ cần tạo đầu kia của kết nối TCP và có ổ khai thác thử nghiệm của bạn mà.

IMO việc sử dụng rộng rãi lớp bộ điều hợp làm xáo trộn các phần quan trọng nhất của thiết kế và cũng có xu hướng loại bỏ nhiều nội dung không được kiểm tra mà thực sự phải được thử nghiệm trong ngữ cảnh. Vì vậy, thay thế là xây dựng giàn giáo thử nghiệm của bạn để bao gồm nhiều hệ thống đang được kiểm tra. Nếu bạn đang xây dựng các bài kiểm tra của bạn từ đầu, bạn vẫn sẽ đạt được khả năng cô lập nguyên nhân của một thất bại cho một lớp hoặc chức năng nhất định, nó sẽ không bị cô lập ...

+0

Điều này sẽ làm cho thử nghiệm một bài kiểm tra tích hợp, và không phải là một bài kiểm tra đơn vị. Nó sẽ chậm hơn, và nhiều khả năng thất bại. Không có gì sai với điều đó, bạn chỉ cần biết về nó (ví dụ, trong giải pháp CI của bạn). –

5

Tôi nghĩ @ Hitchhiker đang đi đúng hướng, nhưng tôi cũng muốn suy nghĩ về việc tóm tắt những thứ như thế chỉ một bước xa hơn.

Tôi sẽ không loại bỏ trực tiếp TcpClient, vì điều đó sẽ vẫn buộc bạn quá chặt chẽ với việc triển khai cơ bản ngay cả khi bạn đã viết các bài kiểm tra. Đó là, việc triển khai của bạn được gắn với một phương thức TcpClient cụ thể. Cá nhân, tôi sẽ cố gắng một cái gì đó như thế này:

[Test] 
    public void TestInput(){ 

     NetworkInputSource mockInput = mocks.CreateMock<NetworkInputSource>(); 
     Consumer c = new Consumer(mockInput); 

     c.ReadAll(); 
    // c.Read(); 
    // c.ReadLine(); 

    } 

    public class TcpClientAdapter : NetworkInputSource 
    { 
     private TcpClient _client; 
     public string ReadAll() 
     { 
      return new StreamReader(_tcpClient.GetStream()).ReadToEnd(); 
     } 

     public string Read() { ... } 
     public string ReadLine() { ... } 
    } 

    public interface NetworkInputSource 
    { 
     public string ReadAll(); 
     public string Read(); 
     public string ReadLine(); 
    } 

thực hiện này sẽ tách bạn khỏi TCP liên quan chi tiết hoàn toàn (nếu đó là một mục tiêu thiết kế), và bạn thậm chí có thể ống ở đầu vào thử nghiệm từ một tập cứng mã hóa các giá trị hoặc tệp đầu vào thử nghiệm. Rất tay nếu bạn đang trên đường thử nghiệm mã của bạn cho một đoạn đường dài.