You need to enable JavaScript to run this app. Python unittest mock正确使用:解决含SSH依赖项目单元测试覆盖率低问题
优惠活动
大模型
产品
解决方案
定价
更多

Python unittest mock正确使用:解决含SSH依赖项目单元测试覆盖率低问题

Python SSH场景单元测试Mock正确用法

原有测试的核心问题

你当前测试覆盖率极低的核心原因是错误的mock了被测对象本身,具体问题如下:

  • 你通过@mock.patch('certificates.Certificates')把要测试的Certificates类整个替换成了模拟对象,所有调用都没有走你写的真实业务逻辑,自然覆盖率极低
  • mock装饰器的参数顺序是从下往上匹配,你当前的参数顺序完全颠倒
  • 没有模拟SSH依赖的完整返回结构,无法匹配业务代码的调用链路
  • 没有覆盖异常分支的测试场景

正确实现思路

单元测试中我们只需要mock外部不稳定依赖,被测的业务类本身绝对不能mock,本次你只需要mock两个依赖:

  1. SSH连接工具类SshConnection,避免真实发起SSH请求
  2. 环境变量os.environ,避免测试依赖本地环境配置

完整测试代码

import os
import unittest
from unittest import mock
from certificates import Certificates  # 引入真实的被测类

# 只mock SSH依赖,不要mock被测的Certificates类
@mock.patch('helpers.ssh_connection.SshConnection')
class TestCertificates(unittest.TestCase):
    def setUp(self):
        # 构造模拟的stdout对象,匹配业务代码中stdout.read().decode().strip()的调用链路
        self.mock_stdout = mock.Mock()
        self.mock_stdout.read.return_value.decode.return_value.strip.return_value = "test_cert_content"

    def test_get_certificates_normal_case(self, MockSsh):
        # 配置模拟的SSH实例的execute_cmd返回值
        mock_ssh_instance = MockSsh.return_value
        mock_ssh_instance.execute_cmd.return_value = (None, self.mock_stdout, None)

        # 实例化真实的被测对象
        cert_obj = Certificates()
        result = cert_obj.get_certificates("test_env")

        # 断言结果符合预期
        self.assertTrue(result)
        # 断言SSH命令被正确调用了2次,参数符合要求
        mock_ssh_instance.execute_cmd.assert_has_calls(
            [
                mock.call("get certificate_1"),
                mock.call("get certificate_2 by using test_env")
            ]
        )

    def test_get_certificates_exception_case(self, MockSsh):
        # 配置execute_cmd调用时抛出RuntimeError,触发异常分支
        mock_ssh_instance = MockSsh.return_value
        mock_ssh_instance.execute_cmd.side_effect = RuntimeError

        cert_obj = Certificates()
        result = cert_obj.get_certificates("test_env")

        # 断言异常分支返回符合预期
        self.assertFalse(result)

    @mock.patch.dict(os.environ, {
        "IP_ADDRESS": "123.123.123.123",
        "SSH_KEY_PATH": "/test/ssh_key",
        "ENV_NAME": "prod_env"
    })
    @mock.patch('certificates.Certificates.get_certificates')  # 只mock本类的get_certificates方法
    def test_main(self, mock_get_cert, MockSsh):
        mock_ssh_instance = MockSsh.return_value
        # 调用真实的main方法
        Certificates().main()

        # 断言SSH连接的打开、关闭方法被正确调用
        mock_ssh_instance.open_connection.assert_called_once_with("123.123.123.123", "/test/ssh_key")
        mock_ssh_instance.close_connection.assert_called_once()
        # 断言get_certificates被正确调用
        mock_get_cert.assert_called_once_with("prod_env")

if __name__ == '__main__':
    unittest.main()

关键Mock要点说明

  • Mock对象定位原则:你要mock的是业务代码中实际import使用的对象路径,比如业务代码从helpers.ssh_connection引入SshConnection,就patch这个路径
  • 返回值结构匹配:模拟依赖的返回值要和真实调用的结构完全一致,比如execute_cmd返回三个对象,stdout需要有read()方法,返回的字节对象要有decode()方法,整个链路要和真实调用对齐
  • 分支覆盖:通过side_effect配置异常抛出,覆盖try-except的异常分支
  • 最小Mock原则:只mock必要的外部依赖,被测的业务逻辑尽量全部走真实代码,才能保证测试的有效性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 03:36:11