有人成功模拟了.NET 中的 Socket 类吗?

发布于 2024-08-01 18:58:46 字数 185 浏览 8 评论 0原文

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

〗斷ホ乔殘χμё〖 2024-08-08 18:58:46

上面的类仅模拟您的发送方法。 这实际上模拟了一个 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 进行测试,然后注入一个 ISocket 来供应用程序使用。

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

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);
        }
转身以后 2024-08-08 18:58:46

每当我在 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);
  }

}

不确定是否满足您的需求,但它是一个选项。

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.

顾忌 2024-08-08 18:58:46

调用 Send 方法时收到 SocketException 的原因是 Send 不是可重写的方法。 为了让 RhinoMocks 能够模拟属性或方法的行为,它必须在接口中定义(然后我们创建模拟)或者是可重写的。

对此的唯一解决方案是创建一个可模拟的包装类(如 thinkzig 建议的那样)。

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

并安 2024-08-08 18:58:46

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

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.

盛装女皇 2024-08-08 18:58:46

您最好创建一个接口并在测试中模拟它,并在代码中实现一个包装类,将所有方法调用转发到 .NET 套接字,如 thinkzig 所说。 看看这个链接,它是同样的问题: 如何在 C# 中模拟文件系统以进行单元测试?

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?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文