Кто-нибудь успешно издевался над классом Socket в.NET?
Я пытаюсь смоделировать класс System.net.Sockets.Socket в C# - я пробовал использовать макеты NUnit, но он не может имитировать конкретные классы. Я также пытался использовать Rhino Mocks, но, похоже, он использовал реальную версию класса, потому что он вызывал исключение SocketException при вызове Send(byte[]). Кто-нибудь успешно создал и использовал макет Socket, используя какой-либо фреймворк?
5 ответов
Всякий раз, когда я сталкиваюсь с подобными проблемами с Moq, я заканчиваю тем, что создаю интерфейс, чтобы абстрагироваться от того, что я не могу высмеять.
Так что в вашем случае у вас может быть интерфейс ISocket, который реализует метод Send. Тогда имейте свои насмешливые рамки вместо этого.
В вашем реальном коде у вас будет такой класс
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);
}
}
Не уверен, что это соответствует вашим потребностям, но это вариант.
Вышеуказанный класс только проверяет ваш метод отправки. Это на самом деле издевается над сокетом. Он наследует весь сокет, а затем реализует интерфейс 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);
}
Причина, по которой вы получаете SocketException при вызове метода Send, заключается в том, что Send не является перезаписываемым методом. Чтобы RhinoMocks мог имитировать поведение свойства или метода, он должен быть либо определен в интерфейсе (который мы затем создаем с помощью нашего макета), либо его можно переопределить.
Ваше единственное решение для этого - создать класс с надёжной оболочкой (как предполагает thinkzig).
Я создал пример консольного приложения, используя метод thinkzig (класс адаптера для Socket). Он использует RhinoMocks и NUnit. Вы можете скачать его здесь: Как издеваться над System.Net.Sockets.Socket.
Вам лучше создать интерфейс и смоделировать его в своем тесте, а также реализовать класс-оболочку в своем коде, который перенаправляет все вызовы методов в сокет.NET, как сказал thinkzig. Посмотрите на эту ссылку, это та же проблема: как вы макете файловую систему в C# для модульного тестирования?