尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

pytest中文教程:从入门到实战的自动化测试框架指南

pytest中文教程:从入门到实战的自动化测试框架指南
📅 发布时间:2026/7/5 14:20:23

1. 项目概述:为什么你需要一份高质量的 pytest 中文文档

如果你正在学习或使用 Python 进行自动化测试,那么pytest这个名字你一定不陌生。它几乎是 Python 测试领域的“事实标准”,以其简洁的语法、强大的功能和丰富的插件生态,让编写测试从一件繁琐的事情变得高效甚至有趣。然而,很多开发者和测试工程师,尤其是刚入门的朋友,在接触 pytest 官方文档时可能会遇到一个不大不小的障碍:官方文档是英文的。

虽然英文是编程世界的通用语言,但面对一个全新的、概念众多的框架,母语阅读带来的理解速度和深度是无可替代的。一份结构清晰、翻译准确、案例丰富的中文文档,能帮你省下大量查字典、猜语义的时间,让你更快地抓住 pytest 的精髓,把精力集中在解决实际的测试问题上。这就是为什么一份好的“pytest 中文文档教程”如此有价值——它不是一个简单的翻译,而是一座连接你与高效测试实践之间的桥梁。

我见过不少团队,因为对 pytest 的一知半解,还在用着笨重的unittest或者写着一堆难以维护的测试脚本。而掌握了 pytest 的核心特性,比如fixture依赖注入、参数化测试、丰富的断言重写,你写出的测试代码会像生产代码一样优雅、模块化。这份教程的目标,就是帮你扫清语言障碍,直达核心,让你能快速上手并深入应用 pytest,构建起可靠、可维护的自动化测试体系。

2. 核心内容架构与学习路径设计

一份优秀的教程,其价值不仅在于内容的准确,更在于结构的合理。它能引导读者由浅入深,建立完整的知识体系,而不是在零散的知识点中迷失。基于 pytest 官方文档的脉络和实际应用中的高频需求,我将这份中文教程的核心内容设计为以下几个循序渐进的模块。

2.1 从零到一的快速入门指南

万事开头难,一个好的开始能极大提升学习信心。快速入门部分的目标是在20分钟内,让一个从未接触过 pytest 的开发者成功运行第一个测试,并理解最基本的运作模式。

这部分的核心是“动手”。我不会一上来就抛出一大堆概念,而是会带你完成三件事:安装、写一个最简单的测试、运行并查看结果。你会看到,pytest 的安装简单到只需一条pip install pytest命令。然后,我会让你创建一个test_sample.py文件,里面可能就两行代码:一个被测试的函数和一个以test_开头的测试函数。最后,在终端输入pytest,神奇的事情就发生了——pytest 会自动发现并运行这个测试,并以清晰的颜色和格式告诉你测试是通过还是失败。

注意:很多新手会卡在“测试发现”这一步。pytest 默认会寻找当前目录及子目录下所有以test_开头或_test结尾的.py文件,并执行其中所有以test_开头的函数。如果你的文件或函数命名不符合这个规则,pytest 就会“看不见”你的测试。这是第一个需要牢记的约定。

通过这个最小化的实践,你立刻就能感受到 pytest 的“约定优于配置”哲学和极简之美。这比阅读十页理论都管用。

2.2 步步为营的操作指南精讲

当你成功运行了第一个测试,接下来就需要系统地学习如何用它来解决实际测试中的各种问题。操作指南部分是整个教程的骨架,它对应着官方文档的“How-to guides”,是解决“如何做”的实战手册。

我会将这部分内容拆解成一系列独立又相互关联的专题,每个专题瞄准一个具体的测试场景:

  • 如何编写和报告断言:这是测试的核心。pytest 的强大之处在于,你可以直接使用 Python 原生的assert语句,而无需记忆assertEqual,assertTrue等一堆方法。当断言失败时,pytest 会提供极其详细的上下文信息,帮你快速定位问题。我会详细展示各种数据类型的断言写法,以及失败信息的解读。
  • 如何使用 fixtures:这是 pytest 的灵魂特性,也是从“会用”到“精通”的关键分水岭。Fixture 提供了一种优雅的 setup/teardown 机制。我会用“数据库连接”这个经典例子来讲解:如何定义一个@pytest.fixture,如何在测试函数中通过参数名来请求它,以及如何设置 fixture 的作用域(函数级、类级、模块级、会话级)。理解作用域是优化测试套件执行速度的关键。
  • 如何参数化测试:当你需要对同一个测试逻辑,用多组不同的输入输出数据进行验证时,重复写多个测试函数是低效的。@pytest.mark.parametrize装饰器可以完美解决这个问题。我会演示如何为一个计算器函数编写一个测试,却能同时测试多组边界值和正常值,让测试覆盖更全面,代码更简洁。
  • 如何标记测试:在实际项目中,你可能只想运行冒烟测试、或者跳过某些尚未完成的测试、或者标记某些预期会失败的测试。pytest 的内置标记(如@pytest.mark.skip,@pytest.mark.xfail) 和自定义标记功能,让你能对测试进行灵活的分类和管理。我会讲解如何运行指定标记的测试子集。

这部分内容我会穿插大量的代码示例,每一个示例都力求贴近真实项目场景,比如测试一个 Web 接口、一个数据处理函数或一个工具类。

2.3 随时查阅的参考指南与深入解析

在掌握了基本操作后,你会遇到更复杂的需求或想深入了解某个功能的细节。这时,你需要的不再是步骤指南,而是一本可以随时翻阅的“词典”和“原理书”。

  • API 参考:这部分会系统性地介绍 pytest 的核心函数、装饰器、钩子(hook)和命令行选项。例如,pytest.main()函数如何以编程方式启动测试;pytest.raises()如何断言代码抛出了特定异常;各种命令行参数如-v(详细输出)、-k(关键字筛选)、-x(遇到失败即停止)的具体用法和组合技巧。我会用表格的形式整理常用命令行选项,方便快速查找。
  • 配置详解:pytest 的行为可以通过pytest.ini、pyproject.toml或setup.cfg文件进行灵活配置。我会详细讲解如何配置测试文件搜索路径、默认的标记定义、如何添加自定义的命令行选项、以及如何配置测试报告格式(例如默认使用pytest -v)。一个良好的项目级配置,能让团队所有成员使用统一的测试标准。
  • 插件生态介绍:pytest 的强大,一半来自于其丰富的插件生态。教程会重点介绍几个“必装”的明星插件:
    • pytest-html: 生成美观的 HTML 测试报告。
    • pytest-xdist: 实现测试的并行运行,大幅缩短测试套件执行时间。
    • pytest-cov: 集成coverage.py,生成代码覆盖率报告。
    • pytest-mock: 集成unittest.mock,方便进行测试替身(mock)操作。
    • allure-pytest: 生成 Allure 框架支持的交互式可视化测试报告,这也是当前企业级自动化测试非常流行的报告形式。我会单独用一小节说明如何安装、配置 allure,并解决像“有用例标题和参数时,标题会被参数挤得换行”这类实际使用中的样式问题。
  • 核心概念解析:为什么 pytest 能重写assert?测试发现(test discovery)的内部机制是怎样的?conftest.py文件的作用域和最佳实践是什么?这些“解释说明”性质的内容,能帮助你从“知其然”到“知其所以然”,当遇到诡异的问题时,你才能从原理层面去分析和解决。

3. 核心特性深度剖析与实战应用

了解了整体框架,我们来深入聊聊 pytest 那些让人爱不释手的核心特性。这些特性是它区别于unittest等传统框架的利器。

3.1 断言:无需记忆的智能断言系统

在unittest中,你需要记住self.assertEqual(a, b),self.assertIn(a, b),self.assertTrue(x)等一长串方法名。在 pytest 中,你只需要写assert a == b,assert a in b,assert x。当断言失败时,pytest 会启动它的“断言重写”机制,不仅仅是告诉你False is not True,它会将表达式的左右两部分值都计算并显示出来。

例如,assert user.name == ‘Admin’如果失败,报告会清晰地显示AssertionError: assert ‘admin’ == ‘Admin’,你一眼就能看出是大小写问题。对于复杂的对象或列表,它会进行智能的差异对比(diff),高亮显示不一致的部分。这个特性极大地简化了断言编写和调试过程。

3.2 Fixture:超越 Setup/Teardown 的依赖管理

Fixture 是 pytest 最标志性的特性。它远不止是setUp和tearDown的替代品,而是一个强大的依赖注入系统。

1. 基本用法与作用域:定义一个 fixture 就像定义一个普通函数,加上@pytest.fixture装饰器。测试函数通过将 fixture 的函数名声明为参数来使用它。作用域(scope)参数决定了 fixture 的创建和销毁频率:

  • function(默认):每个测试函数运行一次。
  • class: 每个测试类运行一次。
  • module: 每个.py文件运行一次。
  • session: 一次测试运行(即一次pytest命令)只运行一次。

合理使用作用域能显著提升测试效率。例如,数据库连接通常使用session作用域,避免每个测试都重复建立连接;而一个干净的临时测试数据,则适合用function作用域。

2. 自动使用(autouse):有些 fixture 你想让某些模块或目录下的所有测试自动使用,而不需要显式声明为参数。这时可以设置autouse=True。比如,一个用于打测试日志的 fixture 就非常适合设为 autouse。

3. 参数化 Fixture:Fixture 本身也可以被参数化,根据不同的参数提供不同的资源。这结合了 fixture 的资源管理能力和参数化测试的数据驱动能力,非常适用于测试需要依赖不同配置的场景。

4.conftest.py文件:这是一个神奇的文件。你可以将多个测试文件共享的 fixture 定义在conftest.py中,pytest 会自动发现它。conftest.py可以放在不同的目录层级,实现 fixture 的层级共享。这是组织大型测试项目的基石。

3.3 参数化:极致的数据驱动测试

@pytest.mark.parametrize装饰器将数据驱动测试提升到了新的高度。你可以在装饰器中定义多组参数,测试函数会依次使用这些参数运行,并被视为多个独立的测试用例。

它的强大之处在于灵活性:

  • 参数可读性:你可以为每组参数指定一个id,在测试报告中清晰显示,而不是晦涩的参数[0]。
  • 组合参数:可以使用多个parametrize装饰器,实现参数的笛卡尔积,全面覆盖多种组合情况。
  • 动态参数:参数列表甚至可以是一个函数调用,实现动态生成测试数据。

这个特性使得编写边界值测试、等价类测试变得异常轻松和规范。

3.4 插件体系:无限扩展的可能性

pytest 本身是一个核心小巧但扩展性极强的框架。几乎所有的高级功能,如并行测试、覆盖率报告、HTML报告、数据库事务回滚、Selenium 集成等,都是通过插件实现的。其插件架构基于pluggy钩子管理库,允许插件在测试生命周期的几乎任何环节进行干预和扩展。

这意味着,当你遇到一个特定的测试需求时,很大概率已经有一个现成的、成熟的插件在等着你。这也意味着,你可以为自己公司的特定测试环境(比如内部的服务网关、中间件)编写定制化的插件,供整个团队使用。学习和理解插件机制,是迈向 pytest 高阶玩家的必经之路。

4. 实战:构建一个分层自动化测试项目

理论说得再多,不如一个实实在在的例子。让我们以一个典型的“Web 接口自动化测试”项目为例,看看如何运用 pytest 的特性,搭建一个结构清晰、易于维护的分层测试框架。这也会涉及到热词中提到的“pytest接口自动化”和“po模型和pytest框架”的结合。

4.1 项目目录结构设计

一个混乱的目录是项目腐化的开始。清晰的分层是可持续维护的关键。我推荐的结构如下:

your_project/ ├── api/ # 接口层(PO模型中的“Page Object”类比) │ ├── __init__.py │ ├── client.py # 封装的HTTP请求客户端(如使用requests) │ ├── user_api.py # 用户相关接口封装 │ └── product_api.py # 产品相关接口封装 ├── tests/ # 测试用例层 │ ├── conftest.py # 项目根目录的共享fixture │ ├── test_data/ # 测试数据文件(JSON, YAML等) │ ├── smoke/ # 冒烟测试套件 │ │ └── test_login.py │ ├── functional/ # 功能测试套件 │ │ ├── conftest.py # 功能测试目录特有的fixture │ │ ├── test_user.py │ │ └── test_product.py │ └── integration/ # 集成测试套件 │ └── test_order_flow.py ├── utils/ # 工具层 │ ├── __init__.py │ ├── logger.py # 日志工具 │ └── data_helper.py # 数据生成/处理工具 ├── reports/ # 测试报告输出目录(由插件生成,.gitignore忽略) ├── pytest.ini # pytest主配置文件 └── requirements.txt # 项目依赖

这个结构体现了“关注点分离”:

  • api/层负责所有与后端接口交互的细节,对外提供简洁的函数调用。这是“PO模型”思想在接口测试中的应用——将“接口”视为一个“对象”,封装其请求方法、URL、参数等。
  • tests/层只关心测试逻辑:准备数据、调用 api 层、做出断言。不同的测试类型(冒烟、功能、集成)放在不同子目录,便于管理和执行。
  • utils/层提供公共工具,避免重复代码。
  • conftest.py可以有多级,用于管理不同范围的共享 fixture。

4.2 核心代码实现与讲解

1. 接口封装层 (api/user_api.py):

import requests from utils.logger import get_logger logger = get_logger(__name__) class UserApi: def __init__(self, base_url): self.base_url = base_url self.session = requests.Session() # 使用session保持会话(如登录态) def login(self, username, password): """登录接口""" url = f"{self.base_url}/api/login" payload = {"username": username, "password": password} logger.info(f"请求登录接口: {url}, 数据: {payload}") response = self.session.post(url, json=payload) logger.info(f"登录响应状态码: {response.status_code}") return response # 返回原始响应,让测试层决定如何断言 def get_user_info(self, user_id): """获取用户信息""" url = f"{self.base_url}/api/users/{user_id}" response = self.session.get(url) return response # ... 其他接口方法

这里的关键是:接口层只做“封装”和“通信”,不做“断言”。它返回原始的响应对象,将验证逻辑完全交给测试层。

2. 测试用例层 (tests/functional/test_user.py):

import pytest from api.user_api import UserApi class TestUserFunctional: """用户功能测试类""" @pytest.mark.parametrize("username, password, expected_code", [ ("admin", "admin123", 200), ("test_user", "wrong_pwd", 401), ("", "admin123", 400), ]) def test_login_with_different_input(self, api_client, username, password, expected_code): """参数化测试登录接口的不同输入""" response = api_client.login(username, password) assert response.status_code == expected_code if expected_code == 200: # 登录成功,断言返回中包含token json_data = response.json() assert "token" in json_data assert len(json_data["token"]) > 10 def test_get_user_info_success(self, api_client, authenticated_client): """测试获取用户信息-需要登录态""" # 使用一个已经过登录的 fixture `authenticated_client` user_api = authenticated_client response = user_api.get_user_info(1) assert response.status_code == 200 user_data = response.json() assert user_data["id"] == 1 assert "username" in user_data @pytest.mark.skip(reason="该接口尚未开发完成") def test_logout(self, authenticated_client): """跳过尚未完成的测试""" # 暂时跳过 pass

3. 核心 Fixture 定义 (tests/conftest.py):

import pytest from api.user_api import UserApi @pytest.fixture(scope="session") def base_url(): """返回基础URL,可以从配置文件或环境变量读取""" return "https://your-test-server.com" @pytest.fixture(scope="session") def api_client(base_url): """提供一个未登录的API客户端会话,session作用域避免重复创建""" client = UserApi(base_url) yield client # 如果需要,可以在这里做session级别的清理,比如关闭所有连接 # client.session.close() @pytest.fixture(scope="function") # 每个测试函数都需要独立的登录态 def authenticated_client(api_client): """提供一个已登录的API客户端fixture""" # 使用测试账号登录 login_resp = api_client.login("test_user", "correct_password") if login_resp.status_code != 200: pytest.fail("预置账号登录失败,无法进行依赖登录的测试") # 登录成功后,api_client的session已携带cookie/token yield api_client # 如果需要,可以在这里登出 (teardown逻辑) # api_client.logout()

这个conftest.py定义了项目级的共享 fixture。authenticated_clientfixture 依赖于api_client,体现了 fixture 的依赖注入特性。scope的合理设置优化了测试速度。

4. 配置文件 (pytest.ini):

[pytest] # 指定测试文件命名规则 python_files = test_*.py # 指定测试类和函数命名规则 python_classes = Test* python_functions = test_* # 自定义标记,防止未注册的标记引发警告 markers = smoke: 冒烟测试用例 slow: 运行缓慢的测试用例 integration: 集成测试用例 # 默认命令行选项 addopts = -v --tb=short --strict-markers # 指定测试目录(可选,默认当前目录) testpaths = tests # 配置日志 log_cli = true log_cli_level = INFO log_cli_format = %(asctime)s [%(levelname)s] %(name)s: %(message)s

这个配置文件统一了项目的测试行为,比如报告格式、标记管理,让所有团队成员执行测试时得到一致的结果。

4.3 测试执行与报告生成

有了上面的结构,执行测试就非常灵活了:

  • 运行全部测试:pytest
  • 运行特定目录:pytest tests/functional/
  • 运行标记为smoke的测试:pytest -m smoke
  • 运行包含‘login’关键字的测试:pytest -k login
  • 并行运行测试(需安装pytest-xdist):pytest -n auto(auto表示使用所有CPU核心)

生成丰富的测试报告:

  1. HTML报告:安装pytest-html后,使用pytest --html=reports/report.html即可生成。报告会包含测试通过率、耗时、失败详情等,非常适合在 CI/CD 流水线中归档。
  2. Allure报告:这是目前最流行的交互式报告之一。安装allure-pytest和 Allure 命令行工具。
    • 执行测试并收集结果:pytest --alluredir=./reports/allure-results
    • 生成并打开报告:allure serve ./reports/allure-resultsAllure 报告提供了美观的仪表盘、用例分类、历史趋势图,并且支持附件(如失败截图、日志文件),对于分析测试结果非常有帮助。关于热词中提到的“有用例标题和参数时,标题会被参数挤得换行”问题,通常可以通过在@pytest.mark.parametrize中为参数组设置更简短的ids,或者在 Allure 的配置中调整样式来解决,核心是控制测试用例名称的长度和格式。

5. 常见问题排查与进阶技巧

即使按照最佳实践来,在实际使用中还是会踩到各种各样的“坑”。这里我总结了一些高频问题和进阶技巧,希望能帮你少走弯路。

5.1 测试发现与执行问题

  • 问题:运行pytest命令后,提示“no tests ran”。
    • 排查:首先检查当前目录和子目录下是否存在符合命名规则(test_*.py或*_test.py)的文件。其次,检查文件内是否有以test_开头的函数或方法。最后,检查pytest.ini或setup.cfg中是否配置了python_files等选项覆盖了默认规则。
  • 问题:如何只运行一个特定的测试文件或测试函数?
    • 解决:pytest path/to/test_file.py::TestClass::test_method。这是最精确的定位方式。也可以使用-k进行关键字过滤。
  • 问题:测试用例执行顺序是随机的吗?如何控制?
    • 解决:pytest 默认按文件、类、方法的名称字母顺序执行。你可以安装pytest-ordering插件来用@pytest.mark.run(order=1)装饰器指定顺序,但不推荐过度依赖执行顺序。好的测试应该是相互独立的。如果确实需要顺序(如集成流程测试),可以考虑将它们放在同一个函数或使用 fixture 的依赖关系来管理。

5.2 Fixture 使用中的“坑”

  • 问题:在 fixture 中yield之前的代码(setup)正常执行,但yield之后的代码(teardown)没有执行。
    • 排查:这通常是因为测试函数或 fixture 本身抛出了异常,导致生成器没有正常完成。确保你的 fixture 能处理可能的异常,或者使用request.addfinalizer方式注册清理函数,这种方式即使 setup 部分失败,已注册的清理函数也会被执行。
  • 问题:autouse=True的 fixture 如何避免对某些测试产生影响?
    • 解决:autousefixture 会对所有测试生效。如果某些测试不需要它,可以通过重写 fixture 或使用更精细的作用域来控制。更好的设计是,除非是全局必需的(如日志初始化),否则尽量少用autouse,而是显式声明依赖。
  • 问题:conftest.py中定义的 fixture 没有被发现。
    • 排查:确保conftest.py文件名称拼写正确。确保运行pytest命令的目录或父级目录下有该文件。pytest 的测试发现会从命令行参数指定的路径(或当前目录)开始向上查找conftest.py。

5.3 断言与调试技巧

  • 问题:复杂的对象断言失败时,输出信息不直观。
    • 解决:pytest 对 Python 标准类型的对比已经做得很好。对于自定义对象,确保其__repr__方法能返回一个清晰的字符串表示,这样在断言失败时就能看到有意义的差异。也可以使用pytest.approx进行浮点数近似比较,避免精度问题导致的失败。
  • 技巧:使用pytest -vvs运行测试。-vv显示更详细的信息,-s禁止捕获标准输出,这样你在测试中打印的print语句或日志就能在控制台显示,对于调试非常有用。
  • 技巧:使用pytest --pdb在测试失败时自动进入 pdb 调试器。这允许你在失败的那一刻检查所有变量和调用栈,是定位复杂问题的终极利器。

5.4 与 CI/CD 及其他工具集成

  • 生成 JUnit XML 报告:许多 CI 系统(如 Jenkins、GitLab CI)都支持 JUnit 格式的测试结果。使用pytest --junit-xml=report.xml生成,CI 系统可以解析该文件并展示通过率、趋势图。
  • 与 Selenium 集成:热词中提到了 “pycharm selenium pytest自动化框架分层目录”。这通常指的是将 Page Object 模式与 pytest 结合。你可以将每个页面封装成一个类(在page_objects/目录),在 fixture 中初始化 WebDriver 并传递给这些页面对象,在测试用例中调用页面对象的方法。这样实现了页面操作逻辑、测试业务逻辑和测试框架的三层分离,是 UI 自动化测试的成熟模式。
  • 管理测试数据:对于复杂的测试数据,不建议硬编码在测试文件中。可以使用@pytest.fixture(params=...)从 JSON、YAML 或 CSV 文件中加载数据。也可以使用pytest-datadir或pytest-datafiles这类插件来管理测试数据文件。

最后,学习 pytest 最好的方式就是“在用中学”。从一个简单的项目开始,尝试用 fixture 管理你的测试资源,用参数化来覆盖更多测试数据,逐步引入插件来增强功能。当你习惯了这种简洁而强大的测试方式后,就再也回不去了。这份中文教程的目的,就是成为你手边最得力的那本“指南”,随时帮你解答疑惑,助你在 Python 自动化测试的道路上越走越顺畅。

相关新闻

  • 无需复杂设置!这款会议APP一键录音不漏关键内容
  • RAG的“语义相似≠真正相关”陷阱:从向量检索到图RAG的架构演进
  • Python的struct,把C语言那套二进制魔法,一把塞进你的字符串

最新新闻

  • Kokoro TTS高级技巧:流式播放、语速调节与音频格式选择终极指南
  • Video2X 6.0.0:让模糊视频重获新生的免费AI神器,性能提升300%
  • 汽车黑客技术完全指南:Security-Paper项目中的车联网安全资源
  • Shopware 6:构建现代化电商平台的终极框架实战指南
  • 基于Playwright的全链路追踪:将UI测试问题定位时间从小时级降至分钟级
  • 开题报告3小时搞定?2026年AI生成开题报告实测,效率暴涨10倍

日新闻

  • 基于YOLOv12的番茄成熟度智能检测系统开发
  • 终极RimWorld模组管理指南:用RimSort告别模组冲突烦恼
  • AI Agent框架开发:从理论到实践的完整指南

周新闻

  • 基于YOLOv12的番茄成熟度智能检测系统开发
  • 终极RimWorld模组管理指南:用RimSort告别模组冲突烦恼
  • AI Agent框架开发:从理论到实践的完整指南

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号