Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Has anyone successfully mocked the Socket class in .NET?

I'm trying to mock out the System.net.Sockets.Socket class in C# - I tried using NUnit mocks but it can't mock concrete classes. I also tried using Rhino Mocks but it seemed to use a real version of the class because it threw a SocketException when Send(byte[]) was called. Has anyone successfully created and used a Socket mock using any mocking framework?

like image 945
Nosrama Avatar asked Aug 11 '09 23:08

Nosrama


3 Answers

The above class only Mocks your Send Method. This actually mocks a Socket. It Inherits all of Socket and then Implements the ISocket interface. ISocket needs to implement the signatures of any Socket methods or properties you need to mock

//internal because only used for test code
internal class SocketWrapper : Socket, ISocket
{
    /// <summary>
    /// Web Socket
    /// </summary>
    public SocketWrapper():base(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
    {
    }

    //use all features of base Socket
}

The interface looks like this with two methods declined:

public interface ISocket
{
    void Connect(IPAddress address, int port);
    int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode);
}

The Class that uses them has 2 constructors. One injects an ISocket for testing and then one that makes it's own Socket that the application uses.

public class HTTPRequestFactory3
{
internal ISocket _socket;


    /// <summary>
    /// Creates a socket and sends/receives information.  Used for mocking to inject ISocket
    /// </summary>
    internal HTTPRequestFactory3(ISocket TheSocket)
    {
     _socket = TheSocket as ISocket;
     this.Setup();
    }

    /// <summary>
    /// Self Injects a new Socket.
    /// </summary>
    public  HTTPRequestFactory3()
    {
        SocketWrapper theSocket = new SocketWrapper();
        _socket = theSocket as ISocket;
        this.Setup();
    }
}

Then your tests can create a ISocket, set up expectations and verify them running all the same code the above class will use with a real socket. This test validates that section code.

   [Test]
   public void NewSocketFactoryCreatesSocketDefaultConstructor()
        {
            webRequestFactory = new HTTPRequestFactory3();
            Assert.NotNull(webRequestFactory._socket);
            Socket testSocket = webRequestFactory._socket as Socket;
            Assert.IsInstanceOf<Socket>(testSocket);
        }
like image 151
MikeF Avatar answered Nov 04 '22 07:11

MikeF


Whenever I run into these kinds of problems with Moq I end up creating an interface to abstract away the thing I can't mock.

So in your instance you might have an ISocket interface that implements the Send method. Then have your mocking framework mock that instead.

In your actual code, you'd have a class like this

public class MySocket : ISocket
{
  System.Net.Sockets.Socket _socket;

  public void MySocket(System.Net.Sockets.Socket theSocket)
  {
    _socket = theSocket;
  }

  public virtual void Send(byte[] stuffToSend)
  {
    _socket.Send(stuffToSend);
  }

}

Not sure if that meets your needs, but it's an option.

like image 45
JamieGaines Avatar answered Nov 04 '22 07:11

JamieGaines


The reason you get a SocketException when you call the Send method is because Send is not an overridable method. For RhinoMocks to be able to mock the behavior of a property or method, it has to either be defined in an interface (which we then create our mock off) or is overridable.

Your only solution to this is to create a mockable wrapper class (as suggested by thinkzig).

like image 30
jpoh Avatar answered Nov 04 '22 07:11

jpoh