2008-09-29 18 views
8

¿Cómo se acercan las personas burlándose de TcpClient (o cosas como TcpClient)?TDD y burlarse de TcpClient

Tengo un servicio que admite un TcpClient. ¿Debería envolver eso en algo más más burlable? ¿Cómo debería abordar esto?

Respuesta

22

Al llegar a las clases de prueba que no son aptas para pruebas (es decir, selladas/sin implementar ninguna interfaz/los métodos no son virtuales), es probable que desee utilizar el patrón de diseño Adapter.

En este patrón, agrega una clase de envoltura que implementa una interfaz. Debería burlarse de la interfaz y asegurarse de que todo su código utiliza esa interfaz en lugar de la clase concreta antipática. Se vería algo como esto:

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

¡Esto es perfecto! ¡Gracias! –

+0

+1 mejor explicación más un buen ejemplo simple – Ahmad

+0

gracias @funkymushroom, corregido –

2

El uso del patrón de adaptador es definitivamente el enfoque TDD estándar para el problema. Sin embargo, también podría crear el otro extremo de la conexión TCP y hacer que su arnés de prueba lo conduzca.

IMO El uso generalizado de la clase de adaptador ofusca las partes más importantes de un diseño, y también tiende a eliminar muchas cosas de la prueba que realmente deben probarse en contexto. Entonces, la alternativa es construir su andamio de prueba para incluir más del sistema bajo prueba. Si estás construyendo tus pruebas desde cero, aún lograrás la capacidad de aislar la causa de una falla en una clase o función determinada, simplemente no será aislada ...

+0

Esto haría que la prueba fuera una prueba de integración, y no una prueba de unidad. Será más lento y más propenso a fallar. No es que haya nada de malo en eso, solo debe tenerlo en cuenta (por ejemplo, en su solución de CI). –

5

Creo @ Hitchhiker está en el camino correcto, pero también me gusta pensar en abstraer cosas así solo un paso más allá.

No me burlaría del TcpClient directamente, porque eso todavía te ataría demasiado a la implementación subyacente aunque hayas escrito pruebas. Es decir, su implementación está vinculada a un método TcpClient específicamente. En lo personal, me gustaría probar algo como esto:

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

Esta aplicación que se desacoplarse de Tcp relacionada detalles por completo (si ese es un objetivo de diseño), e incluso se puede tubería de entrada de prueba de un conjunto codificado de los valores , o un archivo de entrada de prueba. Muy útil si estás en camino a probar tu código a largo plazo.