In one of my C# projects I wanted to add tests for a class that uses System.Net.Sockets.Socket. The problem was that the class (FTPConnection) depended directly on Socket as shown in the following class diagram. So I had to find a way to get rid of this direct dependency and mock the Socket class to be able to test FTPConnection without connecting to a live FTP server for each test.
The problem with mocking System.Net.Sockets.Socket is that it implements no abstract interface and is also sealed (which means you cannot derive from the class). Therefore, you cannot mock the class directly with RhinoMocks (which otherwise would be able to mock the class directly without the need for an interface). So we have a (framework) class to whose source code we have no access (which we would need to add something like Socket : ISocket) and from wich we cannot derive a new class. How do we mock such a seemingly isolated class?
First of all, we need a common interface that we can use for mocking. The problem is that we have to make sure Socket implements this interface (let’s call it ISocket). How do we do that? We find a possible answer to that question in the GoF design patterns catalog:
The adapter design pattern (often referred to as the wrapper pattern or simply a wrapper) translates one interface for a class into a compatible interface. (Wikipedia)
So we have to create an adapter class that implements ISocket and simply delegates all calls to its methods to an instance of Socket. Then we make sure FTPConnection uses the adapter class (or rather ISocket) instead of Socket directly and provide a constructor through which we can inject our own implementation of ISocket (e.g. the mocked one) as shown in the following class diagram.
It is quite a bit of effort to mock the Socket class (you have to define every needed method in ISocket and implement the delegation in SocketAdapter) but it definitely pays off! The resulting design is less coupled due to FTPConnection depending on ISocket instead of Socket directly and can be tested easily by providing a mocked socket that simulates valid or invalid FTP server responses. Examples of how to simulate FTP calls and responses using RhinoMocks are included in my example project below.
Example project in C#
I have created a small console application in C# according to the second class diagram above which demonstrates the mocking of System.Net.Sockets.Socket and produces the output shown in the following screenshot.
You can download the project here:
Thanks thanks thanks! I’ve been struggling with the massive size of my SimpleSocket and SimpleListener test suites for a long time, mainly because I had to have fully implemented Sockets and TcpListeners along with all the threading and synchronization concerns that come along with them. I didn’t know anything about using Callbacks with mock objects, and I never would have thought about using such a simple Adaptor for the socket. Thanks again!