如何Mock Python-On-Whales的docker.ps实现容器运行状态单元测试?
正确Mock Python-On-Whales docker.ps 的单元测试方案
首先明确问题核心:Python-On-Whales 的 docker.ps() 返回的是Container对象列表,如果Mock时返回None或非可迭代对象,会直接触发"对象不可迭代"错误;若返回值不符合脚本逻辑预期,会导致断言失败(比如返回None而非True)。
第一步:先明确目标脚本(check_container.py)的典型结构
假设你的脚本逻辑大致如下(如果和实际不符,可对应调整测试逻辑):
# check_container.py from python_on_whales import docker def is_container_running(container_name: str) -> bool: # 通过filters筛选运行中的目标容器 running_containers = docker.ps(filters={"name": container_name, "status": "running"}) # 存在匹配容器则返回True,否则False return len(running_containers) > 0
第二步:正确的单元测试写法(基于unittest.mock)
测试场景1:容器处于运行状态
from unittest.mock import patch, MagicMock import check_container def test_is_container_running_success(): # 模拟一个符合条件的Container对象(仅需脚本用到的属性,这里是name) mock_container = MagicMock() mock_container.name = "test-mysql" with patch('check_container.docker.ps') as mock_ps: # 让Mock的ps方法返回包含该容器的列表 mock_ps.return_value = [mock_container] # 执行测试 result = check_container.is_container_running("test-mysql") # 断言结果正确 assert result is True # 验证ps方法被正确调用(参数匹配) mock_ps.assert_called_once_with(filters={"name": "test-mysql", "status": "running"})
测试场景2:容器未运行(或不存在)
def test_is_container_running_failure(): with patch('check_container.docker.ps') as mock_ps: # 让Mock的ps方法返回空列表,表示无匹配容器 mock_ps.return_value = [] result = check_container.is_container_running("test-mysql") assert result is False mock_ps.assert_called_once_with(filters={"name": "test-mysql", "status": "running"})
关键注意事项
Mock路径必须准确:
必须Mock脚本中实际导入的docker对象的ps方法。比如你的脚本是from python_on_whales import docker,则要Mockcheck_container.docker.ps,而非python_on_whales.docker.ps——这是Mock最常见的错误点。返回值必须是可迭代的列表:
无论测试成功还是失败场景,Mock的ps方法都要返回列表(空或非空),绝对不能返回None或单个对象,否则脚本中len(running_containers)或遍历操作会直接报错。按需模拟Container对象属性:
如果你的脚本中除了检查列表长度,还会访问容器的其他属性(比如id、status),需要给MagicMock添加对应的属性,比如mock_container.id = "abc123"。
基于pytest-mock的简化写法
如果你用pytest和pytest-mock插件,代码会更简洁:
def test_is_container_running_success_pytest(mocker): mock_container = mocker.MagicMock() mock_container.name = "test-mysql" # 直接用mocker.patch替代with语句 mock_ps = mocker.patch('check_container.docker.ps') mock_ps.return_value = [mock_container] assert check_container.is_container_running("test-mysql") is True mock_ps.assert_called_once_with(filters={"name": "test-mysql", "status": "running"})
内容的提问来源于stack exchange,提问作者Qaldak
相关产品推荐
相关产品推荐

