Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Faking TCP requests in C#

Part of my n00b server:

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

Now I'd like to write unit tests for this snippet. I want to fake a client connection, pass arbitrary data and check how the server handles it.

How should I do it in C#?

edit:
What I'd like to mock is the connection itself - I want to avoid network connections.

like image 738
emesx Avatar asked Apr 03 '12 18:04

emesx


2 Answers

In order to unit-test this, you will probably need to create a layer of abstraction on top of the .NET TCP API. Unit tests usually are for testing the inputs, outputs, and interaction of your code - not for testing the interaction of your code with other APIs. That is the role of integration tests. The layer of abstraction you will create will not not be unit tested, but it will allow you to easily swap it out with a fake or mock object in order to test the rest of your code.

like image 160
Steven Oxley Avatar answered Oct 06 '22 03:10

Steven Oxley


It is not a unit test if it is listening to a socket. Wrap the client and with a thin layer and work with a mock instead. This way you can fake all the received data you want.

E.g. Mocking the socket (simplified example):

Create an interface ISocket with all the methods you need:

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

Now create a concrete class TcpSocket implementing 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
}

Wherever you would normally use a System.Net.Sockets.Socket, pass a ISocket instead. When you need to new up a Socket use TcpSocket. If you create sockets deep down in the guts of your system you might want to create a factory instead of newing up a TcpSocket directly. Under test you can then pass a different implementation of ISocket (the Mock) (possibly created through the factory). You could implement your own mock by creating a second implementation of ISocket called MockSocket which returns test data in Receive or you could use on of the countless mock frameworks to do that for you.

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...
}

This might seen like a lot of effort, but in all but toy systems the boundary api should be hidden behind a thin layer not only for testing but also to stay flexible. If, for instance, you want to use a more powerful socket library instead of System.Net.Socket you can make TcpSocket use that without the need to change every use of sockets in your own code. This is also the reason why programming to an interface instead of programming to a concrete implementation is usually a good idea: you can easily switch implementations (but that doesn't mean you should create interfaces to ALL your classes). If this all confuses you read more about mocking (like here: http://en.wikipedia.org/wiki/Mock_object)

like image 30
EricSchaefer Avatar answered Oct 06 '22 03:10

EricSchaefer