Es handelt sich nicht um einen Einheitstest, wenn er auf einen Socket hört. Umhüllen Sie den Client und mit einer dünnen Schicht und arbeiten Sie stattdessen mit einem Mock. Auf diese Weise können Sie alle empfangenen Daten fälschen, die Sie wollen.
Z.B. Mocking the socket (vereinfachtes Beispiel):
Erstellen Sie eine Schnittstelle ISocket mit allen Methoden, die Sie benötigen:
public interface ISocket
{
ISocket Accept( int port );
byte[] Receive( int numberOfBytes );
bool Send( byte[] data );
void Disconnect();
bool Connect( string address, int port );
}
Erstellen Sie nun eine konkrete Klasse TcpSocket, die ISocket implementiert:
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
}
Wo immer Sie normalerweise einen System.Net.Sockets.Socket verwenden würden, übergeben Sie stattdessen einen ISocket. Wenn Sie einen Socket neu erstellen müssen, verwenden Sie TcpSocket. Wenn Sie Sockets tief in den Eingeweiden Ihres Systems erstellen, möchten Sie vielleicht eine Factory erstellen, anstatt einen TcpSocket direkt neu zu erstellen. Im Test können Sie dann eine andere Implementierung von ISocket (den Mock) übergeben (möglicherweise durch die Factory erstellt). Sie könnten Ihren eigenen Mock implementieren, indem Sie eine zweite Implementierung von ISocket mit dem Namen MockSocket erstellen, die Testdaten in Receive zurückgibt, oder Sie könnten eines der unzähligen Mock-Frameworks verwenden, um dies für Sie zu tun.
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...
}
Dies mag wie ein großer Aufwand erscheinen, aber in allen Systemen, außer in Spielzeugsystemen, sollte die Boundary-Api hinter einer dünnen Schicht versteckt werden, nicht nur zum Testen, sondern auch um flexibel zu bleiben. Wenn Sie z.B. eine leistungsfähigere Socket-Bibliothek anstelle von System.Net.Socket verwenden wollen, können Sie TcpSocket dazu bringen, diese zu verwenden, ohne dass Sie jede Verwendung von Sockets in Ihrem eigenen Code ändern müssen. Das ist auch der Grund, warum es normalerweise eine gute Idee ist, auf eine Schnittstelle statt auf eine konkrete Implementierung zu programmieren: Sie können die Implementierungen leicht wechseln (was aber nicht bedeutet, dass Sie Schnittstellen für ALLE Ihre Klassen erstellen sollten). Wenn Sie das alles verwirrt, lesen Sie mehr über Mocking (wie hier: http://en.wikipedia.org/wiki/Mock_object )