pythonhttpmockingpython-unittest

How to assert an http.client.HTTPSConnection.request


My code tries to make HTTP requests to Gitlab API to make different actions such as create projects, branches, milestones etc. I'm not using external modules like requests because I want to keep my project free of dependencies and I haven't found the need to import any so far. That said I'm trying to assert what my HTTPS Connection requests with a mock in my tests in this way:

gitlab_requests_tests.py

def test_project_creation(self):
        connection = http.client.HTTPSConnection("gitlab.com")
        r = urllib.request.Request(
            method="POST",
            url="https://gitlab.com/api/v4/projects",
            headers={
                "PRIVATE-TOKEN": os.environ.get("ACCESS_TOKEN"),
                "name": Path.cwd().name
            },
        )
        glab_requests.create_project(connection)
        with patch("http.client.HTTPSConnection.request") as https_mock:
            https_mock.assert_called_with(r)

Which tests this code:

gitlab_requests.py

def create_project(connection: http.client.HTTPSConnection):
    header={
        "PRIVATE-TOKEN": os.getenv("ACCESS_TOKEN", default="*"),
        "name": Path.cwd().name
    }
    if re.search(r"[^\w-]", os.getenv("ACCESS_TOKEN", default="*")):
        raise GlabRequestException("Invalid Access token format")
    connection.request("POST", "/api/v4/projects", headers=header)

I know that I asserting my request with url.request.Request isn't the right way to do because it creates a different request object to the one I'm calling from my source code.

How can I assert my request? What am I missing/doing wrong?


Solution

  • I have done following changes to your code:

    1. many changes to your test code (see directly the code and the comments added)
    2. added the custom class Exception: GlabRequestException only to execute the test
    3. added some imports to the file gitlab_requests.py

    File gitlab_requests_tests.py

    import unittest
    from unittest.mock import patch
    import http.client
    import gitlab_requests as glab_requests
    import os
    from pathlib import Path
    
    class MyTestCase(unittest.TestCase):
    
        def test_project_creation(self):
            # I have added this decorator for set the return_value of the function getenv()
            with patch('gitlab_requests.os.getenv') as mock_getenv:
                # return something that not raise a GlabRequestException
                mock_getenv.return_value = 'access_token'
                # the following patch instruction defines the mock object
                # to pass to create_project() that is the code under test
                with patch("http.client.HTTPSConnection") as https_connection_mock:
                    glab_requests.create_project(https_connection_mock)
                    https_connection_mock.request.assert_called_with("POST", "/api/v4/projects", headers={
                        "PRIVATE-TOKEN": os.getenv("ACCESS_TOKEN", default="*"),
                        "name": Path.cwd().name
                    })
    
    if __name__ == '__main__':
        unittest.main()
    

    File gitlab_requests.py

    import http.client
    import re
    import os
    from pathlib import Path
    
    class GlabRequestException(Exception):
        pass
    
    def create_project(connection: http.client.HTTPSConnection):
        header={
            "PRIVATE-TOKEN": os.getenv("ACCESS_TOKEN", default="*"),
            "name": Path.cwd().name
        }
        if re.search(r"[^\w-]", os.getenv("ACCESS_TOKEN", default="*")):
            raise GlabRequestException("Invalid Access token format")
        connection.request("POST", "/api/v4/projects", headers=header)
    

    Output of the execution on my system

    .
    ----------------------------------------------------------------------
    Ran 1 test in 0.001s
    
    OK