You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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分支都不会被执行,自然无法被覆盖率工具统计到

次要问题:

  1. 调用get_log_filename()时未传入必要参数(filepath、filename、env),仅因Mock忽略参数才未报错
  2. 第二个测试中手动调用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')

关键修正点

  1. 移除对get_log_filename的Mock,确保测试执行实际业务代码
  2. 调用函数时传入完整必要参数,符合函数定义
  3. 增加对os.path.exists和os.mkdir调用的断言,验证逻辑执行符合预期
  4. 明确原类的实际名称(原代码中module('dev', ...)是类实例化,需替换为真实类名)

内容的提问来源于stack exchange,提问作者akash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 09:57:54