Test Driven Development With Sockets In C#

Intro

Test Driven Development (TDD) is a type of development that produces robust, clean, and flexible code. While working with Sockets in C#, I found it very hard to practice TDD. Once I found the correct way test sockets, TDD was no problem. In this blog I will go over how to write TDD code with Sockets. First I will go into abstracting the Sockets out of the code. Than I will go into testing the concrete class that are using the sockets, and how to test the socket class wrapper.

Abstract The Sockets Out

The Interface

First make a very thin “Proxy” Interface that will match the socket class methods, 1 to 1 mapping.

Example:

public interface ISocketProxy
{
        bool Connected();
        void Close();
        void Shutdown(SocketShutdown how);
        int Send(byte[] buffer);
        void SendFile(string fileName);
        int Receive(byte[] buffer);
        void Bind(EndPoint localEp);
        void Listen(int backlog);
        ISocketProxy Accept();

}

The reason for this is we are going to pass in mock sockets during our tests.

The Mock

Once we have the interface, it time to make the mock. This is what you will be using for testing. In all your test, that do not test the socket use this class. There a good amount of reasons for this is:

  • Only one socket can be on  a port, so each test will need a unique port.
  • If the test fails the port may not be closed, causing a false positive error when the error is fixed, because a socket can only be on one port.
  • Sending, and receiving data is extremely hard to  do with a live sockets.
  • Mocking Data will give a more reliable test.
  • The set up for a test is so large, short cuts will be taken. Making it impossible to achieve 100% code coverage.
  • You will be testing more than just the class needing to be tested. Meaning if one thing goes wrong, your test could show false positive errors.

Here is an example of a Mock I use:

using System.Net;
using System.Net.Sockets;
using Moq;

public class MockSocketProxy : ISocketProxy
{
	private readonly Mock<ISocketProxy> _mock;
	public MockSocketProxy()
	{
		_mock = new Mock<ISocketProxy>();
	}
	public void Close()
	{
		_mock.Object.Close();
	}
	public bool Connected()
	{
		return _mock.Object.Connected();
	}
	public void Shutdown(SocketShutdown how)
	{
		_mock.Object.Shutdown(how);
	}
	public ISocketProxy Accept()
	{
		return _mock.Object.Accept();
	}
	public void Bind(EndPoint localEp)
	{
		_mock.Object.Bind(localEp);
	}
	public void Listen(int backlog)
	{
		_mock.Object.Listen(backlog);
	}
	public int Receive(byte[] buffer)
	{
		return _mock.Object.Receive(buffer);
	}
	public int Send(byte[] buffer)
	{
		return _mock.Object.Send(buffer);
	}
	public void SendFile(string fileName)
	{
		_mock.Object.SendFile(fileName);
	}
	public void VerifyBind(EndPoint localEp)
	{
		_mock.Verify(m => m.Bind(localEp));
	}
	public void VerifyListen(int backlog)
	{
		_mock.Verify(m => m.Listen(backlog));
	}
	public void VerifySend(byte[] buffer)
	{
		_mock.Verify(m => m.Send(buffer));
	}
	public void VerifyAccept()
	{
		_mock.Verify(m => m.Accept(), Times.Once);
	}
	public void VerifyClose()
	{
		_mock.Verify(m => m.Close(), Times.Once);
	}
	public void VerifyShutdown(SocketShutdown how)
	{
		_mock.Verify(m => m.Shutdown(how), Times.Once);
	}
	public void VerifySendFile(string fileName)
	{
		_mock.Verify(m => m.SendFile(fileName), Times.Once);
	}
	public void VerifyReceive(byte[] buffer)
	{
		_mock.Verify(m => m.Receive(buffer));
	}
}

I have another blog that goes into mocking: https://horvaticblog.wordpress.com/2016/05/18/basic-test-driven-development-mocks-in-c-using-moq/

This mock is what you will be using for testing

The Socket Concrete Class

Now that we have made the Interface, and Mock, its time to make the Concrete wrapper class. This will be used during run time for all our socket request.

Here is an example of the concrete class I made. It must be a 1 to 1 mapping. Any more, and it will be very hard to test.

using System.Net;
using System.Net.Sockets;

public class SocketProxy : ISocketProxy
{
	private readonly Socket _tcpSocket;
	public SocketProxy()
	{
		_tcpSocket = new Socket(AddressFamily.InterNetwork,
			SocketType.Stream, ProtocolType.Tcp);
	}
	public SocketProxy(Socket tcpSocket)
	{
		_tcpSocket = tcpSocket;
	}
	public bool Connected()
	{
		return _tcpSocket.Connected;
	}
	public ISocketProxy Accept()
	{
		return new SocketProxy(_tcpSocket.Accept());
	}
	public void Bind(EndPoint localEp)
	{
		_tcpSocket.Bind(localEp);
	}
	public void Close()
	{
		_tcpSocket.Close();
	}
	public void Listen(int backlog)
	{
		_tcpSocket.Listen(backlog);
	}
	public int Receive(byte[] buffer)
	{
		return _tcpSocket.Receive(buffer);
	}
	public int Send(byte[] buffer)
	{
		return _tcpSocket.Send(buffer);
	}
	public void SendFile(string fileName)
	{
		_tcpSocket.SendFile(fileName);
	}
	public void Shutdown(SocketShutdown how)
	{
		_tcpSocket.Shutdown(how);
	}
}

Notice it is 1 to 1 with the socket class. You can remove un-needed function, like SendFile, but never add a function not 1 to 1!

This is valid example:

using System.Net;
using System.Net.Sockets;

public class SocketProxy : ISocketProxy
{
	private readonly Socket _tcpSocket;
	public SocketProxy()
	{
		_tcpSocket = new Socket(AddressFamily.InterNetwork,
			SocketType.Stream, ProtocolType.Tcp);
	}
	public SocketProxy(Socket tcpSocket)
	{
		_tcpSocket = tcpSocket;
	}
	public bool Connected()
	{
		return _tcpSocket.Connected;
	}
	public ISocketProxy Accept()
	{
		return new SocketProxy(_tcpSocket.Accept());
	}
	public void Bind(EndPoint localEp)
	{
		_tcpSocket.Bind(localEp);
	}
	public void Close()
	{
		_tcpSocket.Close();
	}
	public void Listen(int backlog)
	{
		_tcpSocket.Listen(backlog);
	}
}

But this is not a vaild:

using System.Net;
using System.Net.Sockets;

public class SocketProxy : ISocketProxy
{
	private readonly Socket _tcpSocket;
	public SocketProxy()
	{
		_tcpSocket = new Socket(AddressFamily.InterNetwork,
			SocketType.Stream, ProtocolType.Tcp);
	}
	public SocketProxy(Socket tcpSocket)
	{
		_tcpSocket = tcpSocket;
	}
	public bool Connected()
	{
		return _tcpSocket.Connected;
	}
	public ISocketProxy Accept()
	{
		return new SocketProxy(_tcpSocket.Accept());
	}
	public void Bind(EndPoint localEp)
	{
		_tcpSocket.Bind(localEp);
	}
	public void SuperClose()
	{
		_tcpSocket.Close();
                _tcpSocket.Shutdown(how);
	}
	public void Listen(int backlog)
	{
		_tcpSocket.Listen(backlog);
	}
}

This is no longer 1 to 1, and testing will be difficult. The reason testing will be easier is, because all the socket code will be abstracted out.

Classes That Use A Socket

For a class that will be using a socket, its very simple. Pass the ISocketProxy into the constructor of the object using it.

Here is an example:

public class Server
{
     private readonly ISocketProxy _socket;

     public Server(ISocketProxy socket)
     {
           _socket = socket;
     }

     public void Run()
     {
         ...
     }
}

With this class we can pass it a mock, or a real socket. Making our test of this class, just of this class.

Testing

Concrete Classes Using Sockets

Now that we have our socket mock, and a concrete class to test let make a test for the concrete class.

Will will be using Xunit for testing.

Here is an example test:

using Xunit;
public class ServerTest
{
     [Fact]
     public void Make_Web_Server_Get_Request_Send_Back_Repsonce()
     {
          var mockedSocket = new MockSocketProxy()
          var testServer = new Server(mockedSocket ); //Making a server        
                                                          //with the mocked sockets

          testServer.Run();
	  mockedSocket.VerifyBind(...)
	  mockedSocket.VerifyListen(...)
	  mockedSocket.VerifySend(...)
	  mockedSocket.VerifyAccept()
	  mockedSocket.VerifyClose()
	  mockedSocket.VerifyShutdown(...)
	  mockedSocket.VerifySendFile(...)
	  mockedSocket.VerifyReceive(...)

          ...
	 
     
     }
}

Again this information is available on my blog about Mocks: https://horvaticblog.wordpress.com/2016/05/18/basic-test-driven-development-mocks-in-c-using-moq/

This test will make a server, and make sure all the socket calls where made. You can add more test if needed.

Testing The Socket Wrapper

For the socket Wrapper, a test will look something like this:

using System.Net;
using System.Threading;
using Server.Core;
using Xunit;

namespace Server.Test
{        
         public class SocketProxyTest
        {
	    [Fact]
	     public void Make_Web_Request()
	     {
		var testServer = new Server(new SocketProxy()); //Making a server        
                                                          //with the mocked sockets
		
                new Thread(() => RunServer(testingServer)).Start(); //Start Server  
                                                                    //in another  
                                                                    //thread


		//Set up request to sever
                var wrGeturl = WebRequest.Create(&amp;quot;http://localhost:4321&amp;quot;);
               
                //Make a request to the socket, assuming port is on 4321
		wrGeturl.GetResponse();

                ...
	}
        public void RunServer(Server testServer)
        {
            server.Run();
        }
}

You will notice this test is multi threaded. This is because socket.Accept(), it blocks until a call is made to it. If we did not multi thread the test would never end. Along with this its just a simple web request. GetRespones returns information that can further the testing of the sockets if needed.

Leave a comment