Подделка TCP-запросов в C # - PullRequest
       22

Подделка TCP-запросов в C #

9 голосов
/ 03 апреля 2012

Часть моего сервера 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 #?

edit:То, что я хотел бы посмеяться, это само соединение - я хочу избежать сетевых подключений.

Ответы [ 3 ]

17 голосов
/ 03 апреля 2012

Это не модульный тест, если он слушает сокет. Оберните клиента тонким слоем и вместо этого работайте с макетом. Таким образом, вы можете подделать все полученные данные, которые вы хотите.

например. Насмешка над розеткой (упрощенный пример):

Создайте интерфейс 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. Когда вам нужно обновить Socket, используйте TcpSocket. Если вы создаете сокеты в глубине своей системы, вы можете захотеть создать фабрику вместо того, чтобы обновлять TcpSocket напрямую. В процессе тестирования вы можете пройти другую реализацию ISocket (Mock) (возможно, созданную на заводе). Вы можете реализовать свой собственный макет, создав вторую реализацию ISocket под названием MockSocket, которая возвращает тестовые данные в 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)

3 голосов
/ 03 апреля 2012

Самый простой способ - иметь метод, который принимает Stream и выполняет все операции, которые вы ожидаете с ним.Таким образом, вы можете просто передать MemoryStream, в котором есть нужные данные.Это не поможет протестировать ваш код инициализации клиента, но не было ясно, важно ли это для вас или нет.

Кроме того, не запускайте новый Thread для клиента, используйте Taskили аналогичная методология.

2 голосов
/ 03 апреля 2012

Чтобы выполнить это модульное тестирование, вам, вероятно, потребуется создать слой абстракции поверх .NET TCP API. Модульные тесты обычно предназначены для тестирования входов, выходов и взаимодействия вашего кода, а не для тестирования взаимодействия вашего кода с другими API. Это роль интеграционных тестов. Слой абстракции, который вы создадите, не будет подвергнут модульному тестированию, но он позволит вам легко заменить его поддельным или фиктивным объектом для проверки остальной части вашего кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...