I readily admit to going a bit overboard with unit testing. While I have passing tests, I find my solution to be inelegant, and I'm curious if anyone has a cleaner solution.
The class being tested:
class Config(): def __init__(self): config_parser = ConfigParser() try: self._read_config_file(config_parser) except FileNotFoundError as e: pass self.token = config_parser.get('Tokens', 'Token', ) @staticmethod def _read_config_file(config): if not config.read(os.path.abspath(os.path.join(BASE_DIR, ROOT_DIR, CONFIG_FILE))): raise FileNotFoundError(f'File {CONFIG_FILE} not found at path {BASE_DIR}{ROOT_DIR}') The ugly test:
class TestConfiguration(unittest.TestCase): @mock.patch('config.os.path.abspath') def test_config_init_sets_token(self, mockFilePath: mock.MagicMock): with open('mock_file.ini', 'w') as file: #here's where it gets ugly file.write('[Tokens]\nToken: token') mockFilePath.return_value = 'mock_file.ini' config = Config() self.assertEqual(config.token, 'token') os.remove('mock_file.ini') #quite ugly EDIT: What I mean is I'm creating a file instead of mocking one. Does anyone know how to mock a file object, while having its data set so that it reads ascii text? The class is deeply buried. Other than that, the way ConfigParser sets data with .read() is throwing me off. Granted, the test "works", it doesn't do it nicely.
For those asking about other testing behaviors, here's an example of another test in this class:
@mock.patch('config.os.path.abspath') def test_warning_when_file_not_found(self, mockFilePath: mock.MagicMock): mockFilePath.return_value = 'mock_no_file.ini' with self.assertRaises(FileNotFoundError): config.Config._read_config_file(ConfigParser()) Thank you for your time.
BASE_DIR,ROOT_DIR, andCONFIG_FILEsomething that you can set in the module before instantiating aConfig()instance? What if yourConfigclass accepted as an optional parameter a path to a configuration file?ConfigParser. You should rather be testing that_read_config_filedoes what you mean it to do which is, read a configuration file and raise an exception when it fails to do that..inifile in the.inifile). What's really giving me trouble, here, is how theConfigParserclass sets file information when it calls.read. I'd rather just patch a mocked file object that takes ascii chars to set data, but the way the class is designed doesn't make that intuitive.with self.assertRaises(FileNotFoundError):config.Config._read_config_file(config.ConfigParser())*(weird syntax to get around the hidden method prefix)