2012-04-03 12 views
9

parte del mio server di n00b:richieste Faking TCP in C#

TcpClient client = tcpListener.AcceptTcpClient(); 
Thread clientThread = new Thread(new ParameterizedThreadStart(handleClientRegistration)); 
clientThread.Start(client); 
... 
//and in the clientThread we wait for data 
bytesRead = clientStream.Read(message, 0, 4096); 

Ora mi piacerebbe scrivere unit test per questo frammento. Voglio simulare una connessione client, passare dati arbitrari e verificare come il server lo gestisce.

Come dovrei farlo in C#?

modifica:
Quello che mi piacerebbe prendere in giro è la connessione stessa - Voglio evitare le connessioni di rete.

+0

Penso che devi davvero connetterti alla presa ...? Forse mi manca la tua domanda, ma basta aprire un altro socket, chiamare connect e inviare alcuni dati ...? – Aerik

+0

Questo è esattamente ciò di cui tratta questa domanda: dovrei aprire i socket, o dovrei prendere in giro l'intera interfaccia TCP. Penso che un test corretto non dovrebbe usare una risorsa limitata come l'interfaccia di rete .. o sbaglio. – emesx

risposta

16

Non è un test di unità se sta ascoltando una presa. Avvolgi il client e con un sottile strato e lavora invece con una simulazione. In questo modo puoi falsificare tutti i dati ricevuti che desideri.

E.g. Beffarda presa (esempio semplificato):

Crea un isocket interfaccia con tutti i metodi è necessario scaricare:

public interface ISocket 
{ 
    ISocket Accept(int port); 
    byte[] Receive(int numberOfBytes); 
    bool Send(byte[] data); 
    void Disconnect(); 
    bool Connect(string address, int port); 
} 

Ora creare una classe TCPSocket concreta attuazione isocket:

public class TcpSocket : ISocket 
{ 
    private Socket socket; 
    public TcpSocket() 
    { 
     socket = new Socket(AddressFamily.InterNetwork, 
          SocketType.Stream, ProtocolType.Tcp); 
    } 

    // implement all methods of ISocket by delegating to the internal socket 
} 

Ovunque si farebbe normalmente utilizzare un System.Net.Sockets.Socket, passare invece un ISocket. Quando hai bisogno di un nuovo Socket usa TcpSocket. Se crei socket nel profondo del tuo sistema, potresti voler creare una factory invece di creare un TcpSocket direttamente. Sotto test è possibile quindi passare una diversa implementazione di ISocket (the Mock) (eventualmente creata attraverso la factory). È possibile implementare la propria simulazione creando una seconda implementazione di ISocket chiamata MockSocket che restituisce i dati di test in Receive o si può utilizzare uno degli innumerevoli framework mock per farlo per voi.

public class MockSocket : ISocket 
{ 
    private byte[] testData; 
    public void SetTestData(byte[] data) 
    { 
     testData = data; 
    } 

    public byte[] Receive(int numberOfBytes) 
    { 
     return testData; 
    } 

    // you need to implement all members of ISocket ofcourse... 
} 

Questo potrebbe vedere come un sacco di fatica, ma in tutti, ma i sistemi di giocattoli l'API di confine dovrebbe essere nascosto dietro uno strato sottile non solo per il test, ma anche di rimanere flessibile. Se, ad esempio, si desidera utilizzare una libreria socket più potente invece di System.Net.Socket, è possibile utilizzare TcpSocket senza la necessità di modificare ogni utilizzo di socket nel proprio codice. Questo è anche il motivo per cui programmare un'interfaccia invece di programmare un'implementazione concreta di solito è una buona idea: puoi facilmente cambiare le implementazioni (ma ciò non significa che dovresti creare interfacce per TUTTE le tue classi). Se tutto questo ti confonde, leggi di più su mocking (come qui: http://en.wikipedia.org/wiki/Mock_object)

+2

questa è la strada da percorrere –

+0

Ok. Ho un server TCP: thread, ascolto delle connessioni TCP. E ho un cliente - comunicare con il server. Ora sto testando il sever, quindi cosa dovrei esattamente prendere in giro .. il client? perché .. dal momento che posso costringerlo a inviare qualsiasi dato in qualsiasi modo. Stavo pensando di più a un C# -way di derisione delle interfacce TCP, quindi non viene generato traffico, ecc. Più stile in memoria .. – emesx

+0

Dovresti prendere in giro la classe TcpClient. – EricSchaefer

3

Il modo più semplice sarebbe avere un metodo che prende uno Stream ed esegue qualsiasi operazione ti aspetti su di esso. In questo modo puoi semplicemente passare un MemoryStream con i dati che desideri. Questo non aiuterà a testare il codice di inizializzazione del client, ma non è chiaro se fosse importante per te o meno.

Inoltre, non avviare un nuovo Thread per client, utilizzare invece Task o una metodologia simile.

+0

Grazie per il suggerimento! – emesx

2

Per testare l'unità, è necessario creare un livello di astrazione su .NET TCP API. I test unitari di solito servono per testare gli input, le uscite e l'interazione del tuo codice, non per testare l'interazione del tuo codice con altre API. Questo è il ruolo dei test di integrazione. Lo strato di astrazione che creerai non sarà testato unitamente, ma ti permetterà di cambiarlo facilmente con un oggetto falso o simulato per testare il resto del codice.