在C#中伪造TCP请求我的n00b服务器

问题描述:

部分:在C#中伪造TCP请求我的n00b服务器

TcpClient client = tcpListener.AcceptTcpClient(); 
Thread clientThread = new Thread(new ParameterizedThreadStart(handleClientRegistration)); 
clientThread.Start(client); 
... 
//and in the clientThread we wait for data 
bytesRead = clientStream.Read(message, 0, 4096); 

现在,我想编写单元测试了这个片段。我想伪造客户端连接,传递任意数据并检查服务器如何处理它。

我应该如何在C#中执行此操作?

编辑:
我想嘲笑的是连接本身 - 我想避免网络连接。

+0

我认为你必须真正连接到插座...?也许我错过了你的问题,但只需打开另一个套接字,调用connect并发送一些数据......? – Aerik 2012-04-03 18:44:14

+0

这正是这个问题所关心的:我应该打开套接字,还是应该嘲笑整个TCP接口。我认为一个正确的测试不应该使用像网络接口这样的有限资源。或者我错了。 – emesx 2012-04-03 18:55:11

它不是一个单元测试,如果它正在监听套接字。 用一层薄薄的包裹客户端并用模拟工作。这样你可以伪造你想要的所有收到的数据。

E.g.嘲讽插座(简化的例子):

创建的所有方法的接口的ISocket你需要:

public interface ISocket 
{ 
    ISocket Accept(int port); 
    byte[] Receive(int numberOfBytes); 
    bool Send(byte[] data); 
    void Disconnect(); 
    bool Connect(string address, int port); 
} 

现在创建一个具体类的TCPSocket实施的ISocket:

public class TcpSocket : ISocket 
{ 
    private Socket socket; 
    public TcpSocket() 
    { 
     socket = new Socket(AddressFamily.InterNetwork, 
          SocketType.Stream, ProtocolType.Tcp); 
    } 

    // implement all methods of ISocket by delegating to the internal socket 
} 

无论你通常会使用System.Net.Sockets.Socket,而是传递一个ISocket。当你需要新建一个套接字时使用TcpSocket。如果你在系统的内部创建套接字,你可能需要创建一个工厂,而不是直接创建一个TcpSocket。在测试中,您可以传递不同的ISocket实现(模拟)(可能通过工厂创建)。你可以通过创建第二个名为MockSocket的实现ISocket来实现自己的模拟,它可以在Receive中返回测试数据,或者你可以使用无数的模拟框架为你做这件事。

public class MockSocket : ISocket 
{ 
    private byte[] testData; 
    public void SetTestData(byte[] data) 
    { 
     testData = data; 
    } 

    public byte[] Receive(int numberOfBytes) 
    { 
     return testData; 
    } 

    // you need to implement all members of ISocket ofcourse... 
} 

这可能见过很多的努力,但在所有的玩具,但系统的边界API应该后面的薄层不仅对测试,但还保持灵活性被隐藏。例如,如果您想使用功能更强大的套接字库而不是System.Net.Socket,则可以使TcpSocket使用该套接字库,而无需更改您自己的代码中套接字的每次使用。这也是为什么编程接口而不是编程到具体实现通常是一个好主意的原因:您可以轻松地切换实现(但这并不意味着您应该为所有类创建接口)。如果这一切混淆你读更多关于嘲弄(如在这里:http://en.wikipedia.org/wiki/Mock_object

+2

这是要走的路 – 2012-04-03 18:44:42

+0

好的。我有一个TCP服务器 - 线程,侦听TCP连接。我有一个客户端 - 与服务器通信。现在我正在测试服务器,那么我究竟应该嘲笑客户端?为什么......因为我可以强迫它以任何方式发送任何数据。我正在考虑更多关于C#模拟TCP接口的问题,所以不会产生流量等。更多内存中的样式.. – emesx 2012-04-03 18:55:51

+0

您应该模拟TcpClient类。 – EricSchaefer 2012-04-03 18:59:22

最简单的方法是采取一个方法,需要一个Stream并执行您期望的任何操作。这样,你可以简单地通过一个MemoryStream,它有你想要的数据。这不会帮助你测试你的客户端初始化代码,但不清楚这对你是否重要。

此外,请不要为每个客户启动新的Thread,而应使用Task或类似的方法。

+0

感谢您的提示! – emesx 2012-04-03 18:49:31

为了对此进行单元测试,您可能需要在.NET TCP API上创建一个抽象层。单元测试通常用于测试代码的输入,输出和交互 - 而不是测试代码与其他API的交互。这是集成测试的作用。您将创建的抽象层不会被单元测试,但它可以让您轻松将其与假或模拟对象进行交换,以便测试其余代码。