如何通过实现接口来模拟TCPClient
本文关键字:模拟 TCPClient 接口 何通过 实现 | 更新日期: 2023-09-27 17:53:08
我刚接触计算机科学,对网络知识知之甚少。我实习的时候有个任务。它是通过实现接口来模拟TCPClient。其思想是,由于我们不需要连接到真实服务器,我们只需要一个模拟TCPClient来接收数据、保存数据并发送出去。从我的理解,它只是模拟sendmessage函数在TCPClient??
public interface ITCPClient
{
/// <summary>
/// Event handler when TCP client is connected
/// </summary>
event ConnectionEventHandler Connected;
/// <summary>
/// Event handler for TCP Client on receiving data
/// </summary>
event DataReceivedEventHandler DataReceived;
/// <summary>
/// Event handler when TCP client is disconnect
/// </summary>
event ConnectionEventHandler Disconnected;
/// <summary>
/// Reports error when an error occurs
/// </summary>
event ErrorEventHandler OnError;
/// <summary>
/// Set whether to use HostByteOrder or NetworkByteorder with the socket - gateway expects network byte order
/// </summary>
bool ByteOrder { get; set; }
/// <summary>
/// Returns true if the client is running and connected to the server
/// </summary>
bool IsRunning { get; }
/// <summary>
/// Add the message to the sendqueue. The message will be processed by the ProcessMessage function waiting for the message.
/// </summary>
/// <param name="Message"></param>
void SendMessage(string Message);
/// <summary>
/// Add the message to the sendqueue. The message willbe processed by the ProcessMessage function waiting for the message.
/// </summary>
/// <param name="Message"></param>
void SendMessageHiPriority(string Message);
/// <summary>
/// Starts the client and spawn the thread for processing the message
/// </summary>
void Start();
/// <summary>
/// Disconnects and stops listening for messages
/// </summary>
void StopProcessing();
}
public class MockTCPClient : ITCPClient
{
#region Private Fields
private string msg;
#endregion Private Fields
#region Constructor
public MockTCPClient()
{
//nothing
}
#endregion Constructor
#region event
public event ConnectionEventHandler Connected;
public event ConnectionEventHandler Disconnected;
public event ErrorEventHandler OnError;
public event DataReceivedEventHandler DataReceived;
#endregion event
#region property
//question
public string ReceivedMessage
{
get
{
return msg;
}
set
{
msg = value;
}
}
#endregion property
//question??
private void OnDataReceived(object sender, string e)
{
DataReceivedEventHandler dataReceived = DataReceived;
if (dataReceived != null)
dataReceived(this, e);
}
#region ITCPClient Members
#region properties
public bool ByteOrder { get; set; }
public bool IsRunning { get; }
#endregion properties
public void SendMessage(string Message)
{
msg = Message;
}
public void SendMessageHiPriority(string Message)
{
}
public void Start()
{
}
public void StopProcessing()
{
}
#endregion ITCPClient Members
}
这演示了Moq如何验证你的类调用了它的一个方法。
这个测试
创建一个模拟的ITCPClient
-指定SendMessage
方法是可验证的——换句话说,它的使用将被跟踪。
-验证在模拟对象上调用了SendMessage("test");
测试将失败,因为它从未调用SendMessage("test");
[TestMethod]
public void TestTcpClient()
{
var mockedTcpClient = new Mock<ITCPClient>();
mockedTcpClient.Setup(x => x.SendMessage(It.IsAny<string>())).Verifiable();
//mockedTcpClient.Object.SendMessage("test");
mockedTcpClient.Verify(x=>x.SendMessage("test"));
}
如果我们取消注释调用SendMessage("test")
的行,那么测试将通过。
因此,在"实际"使用中,您将创建Mock
并在测试依赖它的类时使用它来代替ITCPClient
。当它完成后,你可以Verify
,你的类调用SendMessage
,并传递预期的值。
如果你不能使用Moq,这里有一个完全不同的方法:
创建实现ITCPClient
的类,如下所示。您可以将大多数方法保留为空,只实现SendMessage
以及其他一些细节:
public class TcpClientMock : ITCPClient
{
private readonly List<string> _sentMessages;
public TcpClientMock(List<string> sentMessages)
{
_sentMessages = sentMessages;
}
public void SendMessage(string Message)
{
_sentMessages.Add(Message);
}
//rest of non-implemented methods
}
在单元测试中,这样做:
var sentMessages = new List<string>();
var mockedTcpClient = new TcpClientMock(sentMessages);
然后创建您要测试的任何类并对其进行操作。完成后,查看sentMessages
是否包含您期望的消息。
至于接收数据,我认为您需要告诉您的模拟对象引发该事件,以便您可以验证您的类在引发事件时是否按预期响应。您可以像这样为TcpClientMock
添加一个方法:
public void SimulateDataReceived(object sender, DataReceivedEventHandlerArgs args)
{
DataReceived(sender, args);
}
这样,当您设置了依赖于ITCPClient
的类时,您可以在模拟上调用SimulateDataReceived
,使其引发事件,这反过来将导致测试对象响应。