Sometimes I want to unit test the pieces of my code that are close to the transport layer, but often they are so close to the metal that it is hard to separate them.
There’s really not a great way to abstract out the communication layer, so you just have to bite the bullet and do it. One technique I’ve found useful is to just create an interface to stub out the pieces that you use and care about, make a class that implements that interface while (behind the scenes, of course) utilizing the real implementation from Microsoft, and, finally, provide an injectable service to create these objects.
Example
ITcpClient
Here, we expose only the parts that we care about. Additionally, it gives us a way to simplify the implementation a bit. The RemoteEndPoint property is actually on the Client property on the TcpClient – which is type Socket – but it is easier to abstract and type “RemoteEndPoint” than “Client.RemoteEndPoint”. Also, ConnectAsync usually takes an IPEndPoint and an integer port, but the rest of my code is dealing with the IP address as a string. The implementation of this interface (below) can handle that little implementation detail.
TcpClient
The TcpClient implements our interface, and, simply, just routes things through to the real System.Net.Sockets.TcpClient underneath. Since we can’t just directly apply the interface to Microsoft’s TcpClient implementation, this is our next best thing. This class is pretty simple, but it also allows expansion in the future if you need to do some other custom stuff.
Why not make the TcpClient class inherit System.Net.Sockets.TcpClient ?
Well, that’s a good question. It turns out it is pretty easy to convert from a derived class to a base class (that is, to go from my TcpClient to Microsoft’s), but going the other way is pretty annoying. Its possible, but not without the help of some custom code or AutoMapper. So, in this case, if you’re receiving a TCP connection via a TcpListener, you’ll need to call .AcceptTcpClientAsync() to get a TcpClient back. This is great, except that its Microsoft’s TcpClient, not mine. And if you try and cast it to the derived type (mine), you’ll get a runtime exception. No bueno. So, dealing with straight interfaces all the time seems to be a lot better in the long run.
ClientService
This just serves as a way for the rest of our code to create these guys. Everyone just uses interfaces everywhere – that’s the key to being able to unit test things easily. You can mock out the ITcpClient, mock out the ClientService to return your mocked objects, and test away without worrying about anything actually trying to go out over the network.
The same principles can be used for TcpListener, which you’re probably also going to be using if you’re dealing with TcpClients.
Admittedly, it is some extra code. It takes some extra time, and generates a small pile of additional files – but being able to test out your code down to this level is pretty much worth it.