0

I created a Player class that is used to subscribe to a game server as well as responding to pings and applying the AI's algorithm moves. The class works as intended but I am trying to test the functions within it and I am having issues.

Here is my class code:

    import socket
import json
import threading
import time

class Player:
    """
    The Player class is used to subscribe to the game server as well
    as responding to pings and applying the AI's algorithm moves
    """
    def __init__(self, sub_address, game_address, name, matricules):
        self.sub_address = sub_address #input an adress tuple(host, port) for subscribtion processes and Player info passing to game server
        self.game_address = game_address #input an adress tuple(host, port) for ping and game comunnication
        self.name = name #name of the Player
        self.matricules = matricules #List of the two student matricules in str type

    def server_response(self, s):
        """
        This function is used to decode a message (bits ==> json ==> str) from the server.
        Returns the message in str type.
        """
        server_resp = s.recv(2048).decode()
        msg = json.loads(server_resp)
        return(msg)

    def player_response(self, client, response):
        """
        This function is used to encode and send a message (str ==> json ==> str) to the server.
        """
        resp = json.dumps(response).encode('utf8')
        total = 0
        while total < len(resp):
            sent = client.send(resp[total:])
            total += sent

    def sub(self):
        """
        This function passes the subscription request to the game server.
        """
        data = {"request": "subscribe", "port": self.game_address[1],"name": self.name, "matricules": self.matricules}
        print("INFO:inscription:sent player creds: ")
        print(data)
        port = self.sub_address[1]
        with socket.socket() as sub_sock:
            sub_sock.connect(self.sub_address)
            self.player_response(sub_sock, data)
            print("INFO:inscription:player " + self.name + ':' + self.server_response(sub_sock)["response"])

    def begin(self):
        """
        This function initializes a server socket to communicate with the game server.
        """
        self.player_sock = socket.socket()
        self.player_sock.bind(self.game_address)
        self.player_sock.listen()
    
    def comm(self):
        """
        This function handles communication requests from the game server
        """
        while True:
            (client, address) = self.player_sock.accept()
            with client:
                msg = self.server_response(client)
                if msg['request'] == 'ping':
                    self.player_response(client, {'response': 'pong'})
                    print("INFO:player and server are playing at ping pong")
                elif msg['request'] == 'play':
                    print("GAME:\nLives left: " + str(msg['lives']) + "\nErrors: " + str(msg['errors']) + "\nGame state: " + str(msg['state']))
                    # msg = {"response": "move","move": 15,"message": "Fun message"}
                    # self.player_response(client, msg)
    
    def thread(self):
        """
        This function creates a thread using the comm() fuction.
        """
        threading.Thread(target = self.comm).start()

Here is my test code:

    import unittest
from unittest.mock import patch, Mock
from player import Player
import socket


class Test_Player(unittest.TestCase):
    
    @patch('socket.socket')
    def test_player_response(self, mock_socket):
        player = Player(("127.0.0.1", 3000), ("127.0.0.1", 8080), "TheBest", ["20269", "20269"])
        mock_socket = mock_socket.return_value
        player.player_response(mock_socket, {'MY QUERY'})
        mock_socket.assert_called()


if __name__ == '__main__':
    unittest.main()

Here is the error I get:

    ======================================================================
ERROR: test_player_response (__main__.Test_Player)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\basil\AppData\Local\Programs\Python\Python310\lib\unittest\mock.py", line 1369, in patched
    return func(*newargs, **newkeywargs)
File "c:\Users\basil\BestAIOthello\test_player.py", line 14, in test_player_response
    player.player_response(mock_socket, {'response': 'pong'})
File "c:\Users\basil\BestAIOthello\player.py", line 32, in player_response
    while total < len(resp):
TypeError: '<' not supported between instances of 'MagicMock' and 'int'

----------------------------------------------------------------------
Ran 1 test in 0.002s

FAILED (errors=1)

I'm am new to posting questions on stackoverflow so if I was too concise or not enough feel free to tell me.

LEBaz2211
  • 1
  • 1
  • Not sure that's the perfect duplicate, but there are a bazillion questions on the topic of `MagicMock` comparing to `int`; the short version is: It implements `__lt__`, but it always returns `NotImplemented`, so it will never compare to another type unless that type explicitly supports comparisons with `MagicMock` (which none do). – ShadowRanger May 10 '22 at 14:32
  • Okay thanks, so maybe using the Mock class isn't the best way of testing my code. What would be a good alternative ? – LEBaz2211 May 10 '22 at 14:43
  • Low-level code like socket handling probably doesn't belong in your `Player` class. Design it to work with an arbitary-file like object, then write a class whose *sole* responsibility is providing a file-like interface around the socket. – chepner May 10 '22 at 14:44
  • @chepner Thanks for the advice (I'm a bit of a noob in programming so hope I won't annoy you with this next question). The thing is that I don't seem to be able to find help on how to test low level socket handling. Do you know a good method to do that ? – LEBaz2211 May 10 '22 at 15:11

0 Answers0