Python单元测试中如何正确Mock BeautifulSoup4的ResultSet
可行方案说明
你不需要依赖外部HTML文件,也没必要过度MockResultSet——ResultSet本身就是list的子类,存储的元素是BeautifulSoup的Tag对象,你的函数核心逻辑只依赖两个行为:
- 入参可迭代
- 迭代出的元素支持通过
[key]方式取src和alt属性
下面给两种合规的单元测试写法,优先推荐第一种,稳定性最高。
方案1:直接构造最小可用BS4测试对象(推荐)
用BeautifulSoup自带的API构造测试用Tag/ResultSet,行为和真实HTML解析出来的对象完全一致,没有外部IO依赖,运行速度快,完全满足单元测试隔离要求。
from bs4 import BeautifulSoup, ResultSet import pytest from your_module import string_operations def test_prepare_src_and_alt_basic(): # 初始化空解析器,仅用于生成测试标签,不需要传入完整HTML soup = BeautifulSoup("", "html.parser") # 构造测试用img标签,覆盖正常场景、缺省属性场景 img_normal = soup.new_tag("img", src="/img/1.jpg", alt="产品图") img_no_alt = soup.new_tag("img", src="/img/2.jpg") img_no_src = soup.new_tag("img", alt="无效图片") # 构造和select()返回类型完全一致的ResultSet对象 test_input = ResultSet(soup, [img_normal, img_no_alt, img_no_src]) result = string_operations.prepare_src_and_alt(test_input) # 断言结果,对齐BS4真实属性访问行为:不存在的属性返回空字符串,缺失src时会触发KeyError(和线上逻辑一致) assert result["/img/1.jpg"] == "产品图" assert result["/img/2.jpg"] == "" with pytest.raises(KeyError): _ = result["/img/non-exist.jpg"]
如果你觉得构造Tag的写法麻烦,也可以直接把测试用HTML片段写在测试代码里解析,不需要存成外部文件,同样符合隔离要求:
def test_prepare_src_and_alt_with_inline_html(): # 测试HTML直接写在测试用例中,无外部依赖 test_html = """ <img class="full-image" src="string" alt="another_string" /> <img class="full-image" src="demo.jpg" alt="示例图" /> """ soup = BeautifulSoup(test_html, "html.parser") result = string_operations.prepare_src_and_alt(soup.select("img.full-image")) assert result == { "string": "another_string", "demo.jpg": "示例图" }
方案2:Mock入参对象(不推荐)
如果你的测试场景完全不需要依赖BS4的真实行为,也可以直接Mock入参,但要注意必须对齐BS4的属性访问逻辑,否则会出现测试通过、线上报错的问题:
from unittest.mock import Mock import pytest from your_module import string_operations def test_prepare_src_and_alt_with_mock(): # 构造Mock图片对象,模拟[]取属性的行为 def make_mock_img(src, alt): mock_img = Mock() mock_img.__getitem__ = lambda _, k: {"src": src, "alt": alt}[k] return mock_img test_input = [ make_mock_img("mock1.jpg", "mock图1"), make_mock_img("mock2.jpg", "mock图2") ] # 函数不需要入参严格是ResultSet类型,传入可迭代的mock对象列表即可运行 result = string_operations.prepare_src_and_alt(test_input) assert result == {"mock1.jpg": "mock图1", "mock2.jpg": "mock图2"}
不推荐Mock的原因:你的函数和BeautifulSoup逻辑强耦合,Mock出来的对象无法还原真实场景下的边界行为(比如属性缺失时的返回值、特殊字符转义逻辑等),测试参考价值很低。
内容的提问来源于stack exchange,提问作者Dawid1312
相关产品推荐
相关产品推荐

