106 行
7.3 KiB
Python
106 行
7.3 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
新闻资讯与技术文章改版及丰富度测试 (TDD 模式)
|
||
验证文章独立页、移动端模板、首页联动、数据库种子文件及去AI味道规范
|
||
"""
|
||
import os
|
||
import re
|
||
import unittest
|
||
|
||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||
|
||
class TestJournalismAndArticles(unittest.TestCase):
|
||
|
||
def setUp(self):
|
||
self.pc_list_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_journalism', 'list.html')
|
||
self.pc_details_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_journalism', 'details.html')
|
||
self.mobile_list_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_journalism', 'list_e.html')
|
||
self.mobile_details_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_journalism', 'details_e.html')
|
||
self.home_index_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_home', 'index.html')
|
||
self.footer_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_common', 'pc', 'footer.html')
|
||
self.css_path = os.path.join(BASE_DIR, 'public', 'assets', 'addons', 'official', 'css', 'modern_nhc.css')
|
||
self.seed_sql_path = os.path.join(BASE_DIR, 'database', 'seeds', 'journalism_articles.sql')
|
||
|
||
def test_pc_list_template_spec(self):
|
||
"""验证 PC 端文章资讯列表页规范"""
|
||
self.assertTrue(os.path.exists(self.pc_list_path), "PC 文章列表模板 list.html 必须存在")
|
||
content = open(self.pc_list_path, 'r', encoding='utf-8').read()
|
||
self.assertIn("纳海川", content, "必须包含品牌名称【纳海川】")
|
||
self.assertIsNone(re.search(r'纳川(?!海)', content), "严禁将品牌错误简写为【纳川】")
|
||
self.assertFalse(re.search(r'[\U0001F600-\U0001F64F\U0001F300-\U0001F5FF\u2600-\u26FF\u2700-\u27BF]', content), "严禁包含任何 emoji")
|
||
self.assertIn("nhc-article-hero", content, "必须包含现代中式 Hero Banner 容器类")
|
||
self.assertIn("nhc-article-card", content, "必须包含现代中式文章卡片样式类")
|
||
self.assertIn("render", content, "必须包含分页渲染组件")
|
||
|
||
def test_pc_details_template_spec(self):
|
||
"""验证 PC 端文章资讯详情页规范"""
|
||
self.assertTrue(os.path.exists(self.pc_details_path), "PC 文章详情模板 details.html 必须存在")
|
||
content = open(self.pc_details_path, 'r', encoding='utf-8').read()
|
||
self.assertIn("纳海川", content, "必须包含品牌名称【纳海川】")
|
||
self.assertIsNone(re.search(r'纳川(?!海)', content), "严禁将品牌错误简写为【纳川】")
|
||
self.assertFalse(re.search(r'[\U0001F600-\U0001F64F\U0001F300-\U0001F5FF\u2600-\u26FF\u2700-\u27BF]', content), "严禁包含任何 emoji")
|
||
self.assertIn("nhc-article-body", content, "必须包含规范的文章正文排版容器")
|
||
self.assertIn("nhc-breadcrumb", content, "必须包含严谨的面包屑导航")
|
||
self.assertIn("info_previous_next_wrap", content, "必须包含上一篇/下一篇自然导流结构")
|
||
|
||
def test_mobile_templates_spec_and_bugfix(self):
|
||
"""验证移动端模板规范并彻底修复循环变量与遗留链接 Bug"""
|
||
self.assertTrue(os.path.exists(self.mobile_list_path), "移动端列表模板 list_e.html 必须存在")
|
||
self.assertTrue(os.path.exists(self.mobile_details_path), "移动端详情模板 details_e.html 必须存在")
|
||
list_content = open(self.mobile_list_path, 'r', encoding='utf-8').read()
|
||
details_content = open(self.mobile_details_path, 'r', encoding='utf-8').read()
|
||
|
||
# 修复历史遗留 bug:循环中错误使用 $item['id'] 替换为正确的遍历项变量
|
||
self.assertNotIn("official_video/list", details_content, "详情页严禁遗留旧 official_video/list 错误路径")
|
||
self.assertFalse(re.search(r'[\U0001F600-\U0001F64F\U0001F300-\U0001F5FF\u2600-\u26FF\u2700-\u27BF]', list_content), "移动端列表严禁 emoji")
|
||
self.assertFalse(re.search(r'[\U0001F600-\U0001F64F\U0001F300-\U0001F5FF\u2600-\u26FF\u2700-\u27BF]', details_content), "移动端详情严禁 emoji")
|
||
|
||
def test_css_design_tokens_for_articles(self):
|
||
"""验证 CSS 中已包含文章与资讯专属样式定义"""
|
||
css = open(self.css_path, 'r', encoding='utf-8').read()
|
||
self.assertIn(".nhc-article-card", css, "CSS 必须定义 .nhc-article-card 样式")
|
||
self.assertIn(".nhc-article-body", css, "CSS 必须定义 .nhc-article-body 样式")
|
||
|
||
def test_seed_sql_rich_articles(self):
|
||
"""验证数据库种子包含不少于 8 篇扎实深度专业文章"""
|
||
self.assertTrue(os.path.exists(self.seed_sql_path), "数据库种子文件 journalism_articles.sql 必须存在")
|
||
sql = open(self.seed_sql_path, 'r', encoding='utf-8').read()
|
||
|
||
# 验证至少 38 篇优质文章插入 (初始 8 篇 + 新增 30 篇)
|
||
insert_count = (sql.count("INSERT INTO `fa_official_list_journalism`") +
|
||
sql.count("INSERT INTO fa_official_list_journalism") +
|
||
sql.count("REPLACE INTO `fa_official_list_journalism`") +
|
||
sql.count("REPLACE INTO fa_official_list_journalism"))
|
||
self.assertGreaterEqual(insert_count, 38, f"必须有至少 38 篇高质量文章 SQL 写入语句 (当前: {insert_count})")
|
||
|
||
# 验证核心业务主题覆盖
|
||
self.assertIn("微服务", sql, "必须覆盖微服务架构深度文章")
|
||
self.assertIn("智能体", sql, "必须覆盖 AI 智能体/大模型与知识库落地文章")
|
||
self.assertIn("进销存", sql, "必须覆盖全链路进销存与业财一体化文章")
|
||
self.assertIn("收银", sql, "必须覆盖智慧收银容灾与离线记账机制文章")
|
||
self.assertIn("测试驱动开发", sql, "必须覆盖 TDD 测试驱动开发规范文章")
|
||
self.assertIn("缓存", sql, "必须覆盖分布式缓存相关深度文章")
|
||
self.assertIn("分库分表", sql, "必须覆盖数据库分库分表相关文章")
|
||
self.assertIn("先进先出", sql, "必须覆盖批次库存先进先出算法相关文章")
|
||
|
||
# 严禁假大空与 AI 味营销词汇
|
||
for bad_word in ["赋能千行百业", "颠覆式创新", "颠覆传统", "未来已来", "数字化新纪元"]:
|
||
self.assertNotIn(bad_word, sql, f"文章种子严禁包含 AI 味空话:{bad_word}")
|
||
|
||
def test_home_and_footer_linkage(self):
|
||
"""验证首页与页脚自然联动技术洞察板块"""
|
||
home = open(self.home_index_path, 'r', encoding='utf-8').read()
|
||
footer = open(self.footer_path, 'r', encoding='utf-8').read()
|
||
|
||
# 首页必须包含技术洞察/动态资讯展示区块
|
||
has_news_section = "nhc-insights-section" in home or "技术洞察" in home or "研发动态" in home
|
||
self.assertTrue(has_news_section, "首页必须包含技术洞察与研发动态板块")
|
||
|
||
# 页脚必须有技术资讯入口
|
||
has_insights_link = "official_journalism" in footer or "技术洞察" in footer or "新闻资讯" in footer
|
||
self.assertTrue(has_insights_link, "页脚必须包含技术洞察/新闻资讯链接")
|
||
|
||
if __name__ == '__main__':
|
||
unittest.main()
|