lancwl
lancwl

Reputation: 111

How to Mock TCPClient by implementing the interface

I am new to computer science and have few knowledge in network. I got a task in my internship.It is to mock a TCPClient by implement Interface. The idea is that since we don't need to connect to the real server, we just need a mock TCPClient to receive data, save it and send it out. From what I understand, is it just to mock the sendmessage function in 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

}

Upvotes: 3

Views: 6678

Answers (1)

Scott Hannen
Scott Hannen

Reputation: 29312

This demonstrates how Moq can verify that your class calls one of its methods.

This test
- creates a mock of ITCPClient
- specifies that the SendMessage method is verifiable - in other words, its usage will be tracked.
- verifies that SendMessage("test"); has been called on the mocked object.

The test will fail because it never calls 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"));
}

If we uncomment the line that calls SendMessage("test") then the test will pass.

So in "real" usage you would create the Mock and use it in place of an ITCPClient when testing the class that depends on it. When it's done you can Verify that your class called SendMessage and passed the expected value.

If you can't use Moq, here's a totally different approach:

Create a class that implements ITCPClient as follows. You can leave most of the methods empty and just implement SendMessage along with a few other details:

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
}

In your unit test, do this:

var sentMessages = new List<string>();
var mockedTcpClient = new TcpClientMock(sentMessages);

Then create whatever class you're going to test and act on it. When it's done, see if sentMessages contains the message you expect.


As for receiving data, I suppose you'd need to tell your mocked object to raise that event so you could verify that your class responds as expected when the event is raised. You could add a method to TcpClientMock like this:

public void SimulateDataReceived(object sender, DataReceivedEventHandlerArgs args)
{
    DataReceived(sender, args);
}

That way when you've set up your class that depends on ITCPClient you can call SimulateDataReceived on the mock, causing it to raise the event, which in turn will cause your test subject to respond.

Upvotes: 2

Related Questions