Testing a chat app


We have settled on a peer-to-peer encrypted chat app for our capstone project. My task for this week is to set up continuous integration using Github Actions, and set up and plan the tests we will run each time code is pushed to main.

On the to-do list: unit tests for user input in login, as well as encryption. Those should be straightforward. But we also need to write tests for how the sockets interact, and potentially write tests to make sure threads are doing what is expected.

I’ve spent the past few days researching the best ways to write tests for client/server interaction. There is a lot of disagreement on the internet about this. On every stackoverflow post, someone will recommend mock objects, and someone else says using mock objects is pointless, and integration testing should be done instead.

The obvious answer is to do both unit testing with mock objects and integration testing. I have been spinning my wheels trying to wrap my head around how to set up a mock object to be a client or a server. I thrive on examples, so I tried to find a simple one online somewhere. The python docs left much to be desired:

Mock and MagicMock objects create all attributes and methods as you access them and store details of how they have been used. You can configure them, to specify return values or limit what attributes are available, and then make assertions about how they have been used:

>>>
>>> from unittest.mock import MagicMock
>>> thing = ProductionClass()
>>> thing.method = MagicMock(return_value=3)
>>> thing.method(3, 4, 5, key='value')
3
>>> thing.method.assert_called_with(3, 4, 5, key='value')

…what?? I need a real example showing how it’s done. It took me a while but I finally found this stackoverflow post from just over a year ago, that only has 336 views.

socket_handler.py: 

import socket


class MySocketHandler:
    def __init__(self):
        self.host_ip = "127.0.0.1"
        self.server_port = 9999
        self.tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    def send_hello(self):
        data = "hello!"
        try:
            # Establish connection to TCP server and exchange data
            self.tcp_client.connect((self.host_ip, self.server_port))
            self.tcp_client.sendall(data.encode())

            # Read data from the TCP server and close the connection
            received = self.tcp_client.recv(1024)
        finally:
            self.tcp_client.close()
socket_handler_test.py:

import unittest
from unittest.mock import MagicMock, patch
from socket_handler import MySocketHandler


class SocketHandlerTest(unittest.TestCase):
    @patch("socket_handler.socket.socket")
    def test_send_hello(self, socket_mock):
        socket_mock = MagicMock()

        socket_handler = MySocketHandler()
        socket_handler.send_hello()

        self.assertEqual(socket_handler.tcp_client.connect.call_count, 1)
        self.assertEqual(socket_handler.tcp_client.connect.call_args[0][0][0], "127.0.0.1")
        self.assertEqual(socket_handler.tcp_client.connect.call_args[0][0][1], 9999)
        self.assertEqual(socket_handler.tcp_client.recv.call_count, 1)
        self.assertEqual(
            socket_handler.tcp_client.sendall.call_args[0][0],
            bytes("hello!", encoding="utf-8"),
        )

I need to do more research on mock and MagicMock, because it does indeed seem like magic. This example gives me something to start with, but also raises questions: will we have to write a function like the one above that just sends “Hello!”, just for testing purposes? We are planning to write the code as modularly as possible so hopefully we will be able to use a function we are writing anyway. Or have a function that sends a message from client to server that is not visible to any users.

As far as writing tests for threads, everything I’ve read suggests that I shouldn’t even try. I have a feeling that I could spend the whole quarter trying to write code to make testing thread behavior doable, but I have other parts of the project to work on. We can’t let testing get in the way of the project itself.

Print Friendly, PDF & Email

Leave a Reply

Your email address will not be published. Required fields are marked *