【发布时间】:2017-09-07 20:27:16
【问题描述】:
我很乐意承认在单元测试方面有点过火了。 虽然我通过了测试,但我发现我的解决方案并不优雅,我很好奇是否有人有更清洁的解决方案。
被测试的类:
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 文本?班级被深深埋葬。
除此之外,ConfigParser 使用.read() 设置数据的方式让我很反感。当然,测试“有效”,它做得不好。
对于那些询问其他测试行为的人,这里有一个此类测试的示例:
@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())
感谢您的宝贵时间。
【问题讨论】:
-
这似乎不无道理。对于不同的解决方案,您不能在实例化
Config()实例之前在模块中设置BASE_DIR、ROOT_DIR和CONFIG_FILE吗?如果您的Config类作为可选参数接受配置文件的路径怎么办? -
我认为你不应该测试
ConfigParser。您应该测试_read_config_file是否按照您的意思执行,即读取配置文件并在它未能执行此操作时引发异常。 -
谢谢,@larsks。我也看到了该实用程序,但是,目前,我有兴趣将所有与配置相关的信息保存在一个地方(即,将
.ini文件的名称保存在.ini文件中)。真正给我带来麻烦的是ConfigParser类在调用.read时如何设置文件信息。我宁愿只是修补一个使用 ascii 字符来设置数据的模拟文件对象,但是该类的设计方式并不那么直观。 -
@OluwafemiSule - 我也用上面的几种变体进行了测试,如下所示:
with self.assertRaises(FileNotFoundError):config.Config._read_config_file(config.ConfigParser())*(绕过隐藏方法前缀的奇怪语法) -
*上面的错字,(即在Config文件中保留.ini文件的名称)
标签: python python-unittest configparser python-mock