有没有人在.NET中成功模拟过Socket类?

时间:2009-08-11 23:48:47

标签: c# nunit mocking rhino-mocks nunit-mocks

我正在尝试在C#中模拟出System.net.Sockets.Socket类 - 我尝试使用NUnit模拟但它不能模拟具体的类。我也尝试过使用Rhino Mocks,但它似乎使用了该类的真实版本,因为它在调用Send(byte [])时抛出了SocketException。有没有人使用任何模拟框架成功创建和使用Socket模拟?

5 个答案:

答案 0 :(得分:13)

每当我遇到Moq的这些问题时,我最终会创建一个接口来抽象出我无法模拟的东西。

因此,在您的实例中,您可能有一个实现Send方法的ISocket接口。然后让你的模拟框架嘲笑它。

在您的实际代码中,您将拥有类似这样的课程

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);
  }

}

不确定这是否符合您的需求,但这是一种选择。

答案 1 :(得分:2)

调用Send方法时出现SocketException的原因是Send不是可覆盖的方法。为了使RhinoMocks能够模拟属性或方法的行为,它必须在接口中定义(然后我们创建模拟关闭)或者可以覆盖。

您唯一的解决方案是创建一个可模拟的包装类(如thinkzig所示)。

答案 2 :(得分:1)

我使用thinkzig建议的方法(Socket的适配器类)创建了一个示例控制台应用程序。它使用RhinoMocks和NUnit。您可以在此处下载:How to mock System.Net.Sockets.Socket

答案 3 :(得分:1)

以上课程仅模拟你的发送方法。这实际上嘲笑了一个Socket。它继承了所有Socket,然后实现了ISocket接口。 ISocket需要实现模拟

所需的任何Socket方法或属性的签名
//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
}

接口看起来像这样,拒绝了两种方法:

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

使用它们的类有2个构造函数。一个注入一个ISocket用于测试,然后一个使它成为应用程序使用的自己的Socket。

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();
    }
}

然后你的测试可以创建一个ISocket,设置期望并验证它们运行上述类将与真实套接字一起使用的所有相同代码。此测试验证了部分代码。

   [Test]
   public void NewSocketFactoryCreatesSocketDefaultConstructor()
        {
            webRequestFactory = new HTTPRequestFactory3();
            Assert.NotNull(webRequestFactory._socket);
            Socket testSocket = webRequestFactory._socket as Socket;
            Assert.IsInstanceOf<Socket>(testSocket);
        }

答案 4 :(得分:0)

你最好在测试中创建一个接口并对其进行模拟,并在代码中实现一个包装类,将所有方法调用转发给.NET套接字,如thinkzig所说。看看这个链接,问题是:How do you mock out the file system in C# for unit testing?