fix: 修复 7 个失败测试和 1 个错误测试
- 修复 conftest_pptx.py 中元素类型检测:使用 has_text_frame 替代不存在的 MSO_SHAPE.TEXT_BOX - 修复 test_presentation.py 中 3 个测试:使用对象属性访问替代字典访问 - 修复 unit/test_presentation.py 中路径比较问题 - 添加缺失的 mock_template_class fixture 测试通过率: 316/316 (100%) 代码覆盖率: 94%
This commit is contained in:
@@ -14,6 +14,7 @@ sys.path.insert(0, str(project_root))
|
||||
|
||||
# ============= 基础 Fixtures =============
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temp_dir(tmp_path):
|
||||
"""临时目录 fixture,使用 pytest 内置 tmp_path"""
|
||||
@@ -50,19 +51,20 @@ slides:
|
||||
def sample_yaml(temp_dir):
|
||||
"""创建最小测试 YAML 文件"""
|
||||
yaml_path = temp_dir / "test.yaml"
|
||||
yaml_path.write_text(MINIMAL_YAML, encoding='utf-8')
|
||||
yaml_path.write_text(MINIMAL_YAML, encoding="utf-8")
|
||||
return yaml_path
|
||||
|
||||
|
||||
# ============= 图片 Fixtures =============
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_image(temp_dir):
|
||||
"""创建测试图片文件(使用 Pillow 生成简单的 PNG)"""
|
||||
img_path = temp_dir / "test_image.png"
|
||||
# 创建一个简单的红色图片
|
||||
img = Image.new('RGB', (100, 100), color='red')
|
||||
img.save(img_path, 'PNG')
|
||||
img = Image.new("RGB", (100, 100), color="red")
|
||||
img.save(img_path, "PNG")
|
||||
return img_path
|
||||
|
||||
|
||||
@@ -99,21 +101,33 @@ def sample_template(temp_dir):
|
||||
"""创建测试模板目录和文件"""
|
||||
template_dir = temp_dir / "templates"
|
||||
template_dir.mkdir()
|
||||
(template_dir / "title-slide.yaml").write_text(TEMPLATE_YAML, encoding='utf-8')
|
||||
(template_dir / "title-slide.yaml").write_text(TEMPLATE_YAML, encoding="utf-8")
|
||||
return template_dir
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_template_class():
|
||||
"""Mock Template 类,用于单元测试"""
|
||||
from unittest.mock import patch
|
||||
|
||||
with patch("core.presentation.Template") as mock_class:
|
||||
yield mock_class
|
||||
|
||||
|
||||
# ============= PPTX 验证 Fixture =============
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def pptx_validator():
|
||||
"""PPTX 文件验证器实例"""
|
||||
from tests.conftest_pptx import PptxFileValidator
|
||||
|
||||
return PptxFileValidator()
|
||||
|
||||
|
||||
# ============= 测试数据目录 Fixture =============
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fixtures_dir():
|
||||
"""测试数据目录路径"""
|
||||
@@ -122,6 +136,7 @@ def fixtures_dir():
|
||||
|
||||
# ============= 额外的边界情况 Fixtures =============
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def edge_case_yaml_files(fixtures_dir):
|
||||
"""所有边界情况 YAML 文件的路径"""
|
||||
|
||||
@@ -117,9 +117,7 @@ class PptxFileValidator:
|
||||
}
|
||||
|
||||
for shape in slide.shapes:
|
||||
if shape.shape_type == MSO_SHAPE.TEXT_BOX:
|
||||
counts["text_box"] += 1
|
||||
elif hasattr(shape, "image"):
|
||||
if hasattr(shape, "image"):
|
||||
counts["picture"] += 1
|
||||
elif shape.shape_type in [
|
||||
MSO_SHAPE.RECTANGLE,
|
||||
@@ -131,6 +129,8 @@ class PptxFileValidator:
|
||||
counts["table"] += 1
|
||||
elif shape.shape_type == MSO_SHAPE.GROUP:
|
||||
counts["group"] += 1
|
||||
elif hasattr(shape, "has_text_frame") and shape.has_text_frame:
|
||||
counts["text_box"] += 1
|
||||
else:
|
||||
counts["other"] += 1
|
||||
|
||||
|
||||
@@ -87,9 +87,7 @@ slides:
|
||||
# 模板变量应该被替换
|
||||
elements = rendered["elements"]
|
||||
title_elem = next(
|
||||
e
|
||||
for e in elements
|
||||
if e.get("type") == "text" and "Test Title" in e.get("content", "")
|
||||
e for e in elements if e.type == "text" and "Test Title" in e.content
|
||||
)
|
||||
assert title_elem is not None
|
||||
|
||||
@@ -157,8 +155,8 @@ slides:
|
||||
|
||||
# 检查变量是否被正确替换
|
||||
elements = rendered["elements"]
|
||||
assert any("My Title" in e.get("content", "") for e in elements)
|
||||
assert any("My Subtitle" in e.get("content", "") for e in elements)
|
||||
assert any("My Title" in e.content for e in elements)
|
||||
assert any("My Subtitle" in e.content for e in elements)
|
||||
|
||||
|
||||
class TestPresentationWithoutTemplate:
|
||||
@@ -187,4 +185,4 @@ slides:
|
||||
|
||||
# 元素应该直接被渲染
|
||||
assert len(rendered["elements"]) == 1
|
||||
assert rendered["elements"][0]["content"] == "Direct Text"
|
||||
assert rendered["elements"][0].content == "Direct Text"
|
||||
|
||||
@@ -26,7 +26,7 @@ class TestPresentationInit:
|
||||
"""测试带模板目录初始化"""
|
||||
pres = Presentation(str(sample_yaml), str(sample_template))
|
||||
|
||||
assert pres.templates_dir == sample_template
|
||||
assert pres.templates_dir == str(sample_template)
|
||||
assert isinstance(pres.template_cache, dict)
|
||||
|
||||
def test_init_without_templates_dir(self, sample_yaml):
|
||||
@@ -36,8 +36,8 @@ class TestPresentationInit:
|
||||
assert pres.templates_dir is None
|
||||
assert isinstance(pres.template_cache, dict)
|
||||
|
||||
@patch('core.presentation.load_yaml_file')
|
||||
@patch('core.presentation.validate_presentation_yaml')
|
||||
@patch("core.presentation.load_yaml_file")
|
||||
@patch("core.presentation.validate_presentation_yaml")
|
||||
def test_init_loads_yaml(self, mock_validate, mock_load, temp_dir):
|
||||
"""测试初始化时加载 YAML"""
|
||||
mock_data = {"slides": [{"elements": []}]}
|
||||
@@ -121,7 +121,7 @@ slides:
|
||||
class TestGetTemplate:
|
||||
"""get_template 方法测试类"""
|
||||
|
||||
@patch('core.presentation.Template')
|
||||
@patch("core.presentation.Template")
|
||||
def test_get_template_caches_template(self, mock_template_class, sample_template):
|
||||
"""测试模板被缓存"""
|
||||
mock_template = Mock()
|
||||
@@ -145,8 +145,10 @@ slides:
|
||||
# 应该是同一个实例
|
||||
assert template1 is template2
|
||||
|
||||
@patch('core.presentation.Template')
|
||||
def test_get_template_creates_new_template(self, mock_template_class, sample_template):
|
||||
@patch("core.presentation.Template")
|
||||
def test_get_template_creates_new_template(
|
||||
self, mock_template_class, sample_template
|
||||
):
|
||||
"""测试创建新模板"""
|
||||
mock_template = Mock()
|
||||
mock_template_class.return_value = mock_template
|
||||
@@ -172,7 +174,7 @@ slides:
|
||||
pres = Presentation(str(sample_yaml))
|
||||
|
||||
# 应该在调用 Template 时失败,而不是 get_template
|
||||
with patch('core.presentation.Template') as mock_template_class:
|
||||
with patch("core.presentation.Template") as mock_template_class:
|
||||
mock_template_class.side_effect = YAMLError("No template dir")
|
||||
|
||||
with pytest.raises(YAMLError):
|
||||
@@ -198,12 +200,19 @@ class TestRenderSlide:
|
||||
assert len(result["elements"]) == 1
|
||||
assert result["elements"][0].content == "Test"
|
||||
|
||||
@patch('core.presentation.Template')
|
||||
def test_render_slide_with_template(self, mock_template_class, temp_dir, sample_template):
|
||||
@patch("core.presentation.Template")
|
||||
def test_render_slide_with_template(
|
||||
self, mock_template_class, temp_dir, sample_template
|
||||
):
|
||||
"""测试渲染使用模板的幻灯片"""
|
||||
mock_template = Mock()
|
||||
mock_template.render.return_value = [
|
||||
{"type": "text", "content": "Template Title", "box": [0, 0, 1, 1], "font": {}}
|
||||
{
|
||||
"type": "text",
|
||||
"content": "Template Title",
|
||||
"box": [0, 0, 1, 1],
|
||||
"font": {},
|
||||
}
|
||||
]
|
||||
mock_template_class.return_value = mock_template
|
||||
|
||||
@@ -216,10 +225,7 @@ slides:
|
||||
|
||||
pres = Presentation(str(yaml_path), str(sample_template))
|
||||
|
||||
slide_data = {
|
||||
"template": "title-slide",
|
||||
"vars": {"title": "My Title"}
|
||||
}
|
||||
slide_data = {"template": "title-slide", "vars": {"title": "My Title"}}
|
||||
|
||||
result = pres.render_slide(slide_data)
|
||||
|
||||
@@ -231,10 +237,7 @@ slides:
|
||||
"""测试渲染带背景的幻灯片"""
|
||||
pres = Presentation(str(sample_yaml))
|
||||
|
||||
slide_data = {
|
||||
"background": {"color": "#ffffff"},
|
||||
"elements": []
|
||||
}
|
||||
slide_data = {"background": {"color": "#ffffff"}, "elements": []}
|
||||
|
||||
result = pres.render_slide(slide_data)
|
||||
|
||||
@@ -244,16 +247,16 @@ slides:
|
||||
"""测试渲染无背景的幻灯片"""
|
||||
pres = Presentation(str(sample_yaml))
|
||||
|
||||
slide_data = {
|
||||
"elements": []
|
||||
}
|
||||
slide_data = {"elements": []}
|
||||
|
||||
result = pres.render_slide(slide_data)
|
||||
|
||||
assert result["background"] is None
|
||||
|
||||
@patch('core.presentation.create_element')
|
||||
def test_render_slide_converts_dict_to_objects(self, mock_create_element, sample_yaml):
|
||||
@patch("core.presentation.create_element")
|
||||
def test_render_slide_converts_dict_to_objects(
|
||||
self, mock_create_element, sample_yaml
|
||||
):
|
||||
"""测试字典转换为元素对象"""
|
||||
mock_elem = Mock()
|
||||
mock_create_element.return_value = mock_elem
|
||||
@@ -272,7 +275,9 @@ slides:
|
||||
mock_create_element.assert_called()
|
||||
assert result["elements"][0] == mock_elem
|
||||
|
||||
def test_render_slide_with_template_merges_background(self, mock_template_class, temp_dir, sample_template):
|
||||
def test_render_slide_with_template_merges_background(
|
||||
self, mock_template_class, temp_dir, sample_template
|
||||
):
|
||||
"""测试使用模板时合并背景"""
|
||||
mock_template = Mock()
|
||||
mock_template.render.return_value = [
|
||||
@@ -292,7 +297,7 @@ slides:
|
||||
slide_data = {
|
||||
"template": "test",
|
||||
"vars": {},
|
||||
"background": {"color": "#ff0000"}
|
||||
"background": {"color": "#ff0000"},
|
||||
}
|
||||
|
||||
result = pres.render_slide(slide_data)
|
||||
@@ -304,16 +309,16 @@ slides:
|
||||
"""测试空元素列表"""
|
||||
pres = Presentation(str(sample_yaml))
|
||||
|
||||
slide_data = {
|
||||
"elements": []
|
||||
}
|
||||
slide_data = {"elements": []}
|
||||
|
||||
result = pres.render_slide(slide_data)
|
||||
|
||||
assert result["elements"] == []
|
||||
|
||||
@patch('core.presentation.create_element')
|
||||
def test_render_slide_with_multiple_elements(self, mock_create_element, sample_yaml):
|
||||
@patch("core.presentation.create_element")
|
||||
def test_render_slide_with_multiple_elements(
|
||||
self, mock_create_element, sample_yaml
|
||||
):
|
||||
"""测试多个元素"""
|
||||
mock_elem1 = Mock()
|
||||
mock_elem2 = Mock()
|
||||
@@ -324,7 +329,7 @@ slides:
|
||||
slide_data = {
|
||||
"elements": [
|
||||
{"type": "text", "content": "T1", "box": [0, 0, 1, 1], "font": {}},
|
||||
{"type": "text", "content": "T2", "box": [1, 1, 1, 1], "font": {}}
|
||||
{"type": "text", "content": "T2", "box": [1, 1, 1, 1], "font": {}},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user