在导入模块中 Python 单元测试中模拟文件
Mocking Files In Python Unittest In Imported Modules
我欣然承认在单元测试方面有点过火了。
当我通过测试时,我发现我的解决方案不够优雅,我很好奇是否有人有更简洁的解决方案。
正在测试的class:
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}')
丑陋的测试:
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
编辑:我的意思是我正在创建一个文件而不是模拟一个文件。
有谁知道如何 mock
文件对象,同时设置其数据以便读取 ascii 文本? class 深埋。
除此之外,ConfigParser
使用 .read()
设置数据的方式让我很反感。诚然,测试 "works",它做的并不好。
对于那些询问其他测试行为的人,这里是另一个测试的例子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())
感谢您的宝贵时间。
找到了!
我不得不从一些导入开始:from io import TextIOWrapper, BytesIO
这允许创建文件对象:TextIOWrapper(BytesIO(b'<StringContentHere>'))
下一部分涉及深入研究 configparser
模块以查看它调用 open()
,以便 mock.patch
行为,这里我们有它,一个独立的单元测试!
@mock.patch('configparser.open')
def test_bot_init_sets_token(self, mockFileOpen: mock.MagicMock):
mockFileOpen.return_value = TextIOWrapper(BytesIO(b'[Tokens]\nToken: token'))
config = Config()
self.assertEqual(config.token, 'token')
我欣然承认在单元测试方面有点过火了。 当我通过测试时,我发现我的解决方案不够优雅,我很好奇是否有人有更简洁的解决方案。
正在测试的class:
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}')
丑陋的测试:
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
编辑:我的意思是我正在创建一个文件而不是模拟一个文件。
有谁知道如何 mock
文件对象,同时设置其数据以便读取 ascii 文本? class 深埋。
除此之外,ConfigParser
使用 .read()
设置数据的方式让我很反感。诚然,测试 "works",它做的并不好。
对于那些询问其他测试行为的人,这里是另一个测试的例子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())
感谢您的宝贵时间。
找到了!
我不得不从一些导入开始:from io import TextIOWrapper, BytesIO
这允许创建文件对象:TextIOWrapper(BytesIO(b'<StringContentHere>'))
下一部分涉及深入研究 configparser
模块以查看它调用 open()
,以便 mock.patch
行为,这里我们有它,一个独立的单元测试!
@mock.patch('configparser.open')
def test_bot_init_sets_token(self, mockFileOpen: mock.MagicMock):
mockFileOpen.return_value = TextIOWrapper(BytesIO(b'[Tokens]\nToken: token'))
config = Config()
self.assertEqual(config.token, 'token')