10

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?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Nosrama
  • 14,530
  • 13
  • 49
  • 58

5 Answers5

16

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.

JamieGaines
  • 2,062
  • 1
  • 18
  • 20
  • You should consider making the send method virtual too :) – Chris Missal Aug 12 '09 at 11:58
  • Good call. Edited to make Send method virtual. – JamieGaines Aug 12 '09 at 13:19
  • 4
    But don't stop there. Rather than just echoing the external API, write an interface that describes what your code wants from the communication layer. This might mean that it accepts more structured input, rather than bytes. Or something else, it depends on the context. – Steve Freeman Sep 07 '09 at 11:45
  • 4
    But, if you make this interface more complicated you will need to unit test it, which will mean needing to mock the internal components again... kind of defeats the purpose. – Erik Funkenbusch Dec 28 '09 at 17:51
  • I've written some code to auto-generate an assembly with such interfaces and proxies (for sealed/static methods and types). See http://jolt.codeplex.com/wikipage?title=Jolt.Testing.CodeGeneration.Proxy&referringTitle=Jolt.Testing for more information. – Steve Guidi Dec 28 '09 at 18:18
  • Modifying the interface is a perfectly acceptable thing to do. It's called the Adapter pattern. And, yes, the code inside the adapter (that translates the structured input into the byte array) will need to be unit tested. But, in reality, that code should not be a part of the adapter class. Rather, it should be in a converter class with its own unit tests. The adapter class, then, becomes a client of the tested code. (Remember, it's only necessary to test that which might fail. The single line of code in the adapter to call the converter is maybe not worth the effort.) – aridlehoover Jan 23 '10 at 07:07
3

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);
        }
MikeF
  • 764
  • 9
  • 26
2

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

jpoh
  • 4,536
  • 4
  • 35
  • 60
1

I've created an example console application using the method thinkzig suggests (an adapter class for Socket). It uses RhinoMocks and NUnit. You can download it here: How to mock System.Net.Sockets.Socket.

0

You'd better to create an interface and mock it in your test, and implement a wrapper class in your code, that forward all method calls to .NET socket as thinkzig said. Look at this link, it's same issue: How do you mock out the file system in C# for unit testing?

Community
  • 1
  • 1
Tien Do
  • 10,319
  • 6
  • 41
  • 42