Python Mock测试:os模块与if-else逻辑else分支未被覆盖求助
问题:Mock函数后代码覆盖率未统计到else分支
问题背景
我编写了如下代码,尝试通过各种方式Mock整个函数,但代码覆盖率始终未统计到else分支。已查阅相关资料,未找到适配方案,目前对Mock机制仍有困惑,恳请帮助分析原因及解决方法。
模块代码(module.py)
def get_log_filename(filepath, filename, env): if os.path.exists(filepath): logs = filepath+filename+env+".log" else: os.mkdir(filepath) logs = filepath+filename+env+".log" return logs
测试用例(test_module.py)
import unittest import module from unittest.mock import Mock, patch, MagicMock class TestModule(unittest.TestCase): def setUp(self): self.logpath = os.path.join('/home') self.logconfigpath = os.path.join('/home/config') self.logfile = 'test_case_run' self.logdata = module('dev', self.logpath, self.logfile, self.logconfigpath) # 原模块为类,包含__init__方法 @patch('module.os') @patch.object(module, 'get_log_filename', return_value = 'filename.log') def test_log_file_name(self, mockpath, mockext): mockext.path.exists.return_value = True module.get_log_filename() self.assertEqual(module.get_log_filename(), "filename.log") @patch('module.os') @patch.object(module, 'get_log_filename', return_value = 'filename.log') def test_log_file_names(self, mockpath, mockos): mockos.path.exists.return_value = False module.get_log_filename() mockos.mkdir() self.assertEqual(module.get_log_filename(), "filename.log")
测试用例执行成功,但代码覆盖率未覆盖主函数的else分支,请问哪里出错了?该如何修正?
错误原因
核心错误是直接Mock了要测试的目标函数get_log_filename:
- 用
@patch.object(module, 'get_log_filename', ...)装饰后,原函数被完全替换为返回固定值的Mock对象,调用module.get_log_filename()时执行的是Mock而非实际业务代码 - 不管
os.path.exists返回True还是False,原函数的if/else分支都不会被执行,自然无法被覆盖率工具统计到
次要问题:
- 调用
get_log_filename()时未传入必要参数(filepath、filename、env),仅因Mock忽略参数才未报错 - 第二个测试中手动调用
mockos.mkdir(),这步本该由原函数else分支触发,现在脱离了业务逻辑的触发路径
修正方案
正确做法是只Mock依赖的os模块,保留目标函数的实际执行,通过控制os.path.exists的返回值覆盖两个分支:
修正后的测试用例
import unittest import os import module from unittest.mock import patch class TestModule(unittest.TestCase): def setUp(self): self.logpath = os.path.join('/home') self.logconfigpath = os.path.join('/home/config') self.logfile = 'test_case_run' # 替换为原模块中实际的类名,比如module.LogManager self.logdata = module.YourClassName('dev', self.logpath, self.logfile, self.logconfigpath) @patch('module.os') def test_log_filename_existing_path(self, mock_os): # 模拟路径已存在的场景 mock_os.path.exists.return_value = True # 传入完整参数调用原函数 result = module.get_log_filename('/home', 'test_case_run', 'dev') # 验证返回值 self.assertEqual(result, '/hometest_case_rundev.log') # 验证依赖方法的调用情况 mock_os.path.exists.assert_called_once_with('/home') mock_os.mkdir.assert_not_called() @patch('module.os') def test_log_filename_new_path(self, mock_os): # 模拟路径不存在的场景 mock_os.path.exists.return_value = False # 传入完整参数调用原函数 result = module.get_log_filename('/home', 'test_case_run', 'dev') # 验证返回值 self.assertEqual(result, '/hometest_case_rundev.log') # 验证依赖方法的调用情况 mock_os.path.exists.assert_called_once_with('/home') mock_os.mkdir.assert_called_once_with('/home')
关键修正点
- 移除对
get_log_filename的Mock,确保测试执行实际业务代码 - 调用函数时传入完整必要参数,符合函数定义
- 增加对
os.path.exists和os.mkdir调用的断言,验证逻辑执行符合预期 - 明确原类的实际名称(原代码中
module('dev', ...)是类实例化,需替换为真实类名)
内容的提问来源于stack exchange,提问作者akash
相关产品推荐
相关产品推荐

