aim: I want to test our web service Connection Wrapper for e.g. GitLab, SFTP, MySQL.
I am stuck in the following part:
config = configparser.ConfigParser()
config.read(r"C:\git\config.ini")
How do I mock/patch/MagicMock so that config[<section_name>]
is returning a in test_gitlab.py defined value for the given key. As we got various calls of the above structure in various .py files , I'd like, if somehow possible, not change the actual config.read(r"C:\git\config.ini")
call.
Approaches that seemed promising but failed:
configparser.ConfigParser.read.return_value = config_dict
--> this does not alter the variable config, instead returns the dict which (best-case) does not get saved or breaks the runconfig.add_section('GITLAB_TEST'), config.set('GITLAB_TEST', 'token', 'test_token')
--> config and its defined sections are overwritten in gitlab.py as config = configparser.ConfigParser()
# ./module/io/gitlab.py
import configparser
import os
import sys
import gitlab
class GitlabApi:
def __init__(self, client=None):
if sys.platform == "win32":
config = configparser.ConfigParser()
config.read(r"C:\git\config.ini")
self.token = config["GITLAB_{}".format(client)]["token"]
def return_client(self):
self.api = gitlab.Gitlab(
"https://gitlab.company_name.com",
private_token=self.token
)
self.api.auth()
return self.api
# ./tests/test_gitlab.py
import pytest
from unittest.mock import MagicMock
from unittest.mock import Mock
from ane.io import gitlab
def test_return_client_win32():
gitlab.sys = Mock(platform="win32")
gitlab.gitlab.Gitlab = MagicMock()
test_client, expected_private_token, expected_url = "test", "test_token", "test_url"
config_dict = {
"GITLAB_TEST": {"token": "test_token"},
"GITLAB_SCRIPTS": {"token": "script_token"},
}
# following does not work
gitlab.configparser.ConfigParser = MagicMock()
gitlab.configparser.ConfigParser.return_value.read.return_value = config_dict
gitlab.GitlabApi(client=test_client) # mocked object
gitlab.gitlab.Gitlab.assert_called_once_with(
expected_url, private_token=expected_private_token
)
A few stackoverflows that did not solve it for me, but might help others:
python 3.7
My solution to the above stated question: Mocking built-in open() which config.read() calls. The returned fake_config_file
is basically a file in bytes.
def test_return_client_win32():
gitlab.sys = Mock(platform="win32")
gitlab.gitlab.Gitlab = MagicMock()
test_client = 'client'
expected_private_token = 'expected_private_token'
expected_url = "https://gitlab.company.name"
fake_config_file = TextIOWrapper(
BytesIO(
b"[GITLAB_TEST]\ntoken: test_token\n"
b"[GITLAB_SCRIPTS]\ntoken: script_token"
)
)
gitlab.configparser.open = MagicMock(return_value=fake_config_file)
gitlab.GitlabApi(client=test_client)
gitlab.gitlab.Gitlab.assert_called_once_with(
expected_url, private_token=expected_private_token
)
In General, my advised approach at the moment is: Look for a string-type return. Go deep into the methods until you find a method that returns a string or similar. This is what you mock.