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

基于pytest的接口自动化测试框架搭建与实战指南

基于pytest的接口自动化测试框架搭建与实战指南
📅 发布时间:2026/6/30 20:11:36

1. 项目概述:从脚本到框架的接口测试进阶

如果你已经用Python的requests库写过一些零散的接口测试脚本,可能会发现几个头疼的问题:脚本一多就难以管理,每次运行都要手动执行一堆文件;一个接口失败,整个测试流程就中断了,看不到其他接口的情况;测试报告简陋,除了控制台打印,很难给团队一个直观的结果。这正是我们需要一个测试框架的原因。pytest,作为Python生态中最主流的测试框架,它能完美解决这些问题。它不仅仅是一个“运行器”,更提供了一套完整的组织、发现、运行和报告机制。今天我们不谈理论,直接上手,用pytest来重构和升级你的接口测试代码,看看如何从散兵游勇变成一支纪律严明的自动化测试部队。

2. 环境准备与基础框架搭建

2.1 核心依赖安装与虚拟环境管理

工欲善其事,必先利其器。第一步是搭建一个干净、可复现的Python环境。我强烈建议使用虚拟环境,它能将项目依赖与系统Python环境隔离,避免版本冲突。

# 创建项目目录并进入 mkdir api_test_with_pytest && cd api_test_with_pytest # 创建虚拟环境(以venv为例,conda同理) python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # Linux/Mac: source venv/bin/activate

激活虚拟环境后,命令行提示符前通常会显示(venv),表明你已进入隔离环境。接下来安装核心包:

pip install pytest requests pytest-html

这里解释一下为什么是这三个:

  • pytest: 测试框架本体,提供核心的运行、发现、断言功能。
  • requests: 这是发起HTTP请求的事实标准库,我们的接口测试动作全靠它。
  • pytest-html: 一个用于生成美观HTML测试报告的插件。原生的pytest报告在控制台,pytest-html能生成一个独立的HTML文件,包含通过/失败统计、用例详情、日志等,非常适合在团队内分享和存档。

注意:依赖版本管理很重要。建议将当前环境的所有包版本冻结到一个requirements.txt文件中,方便他人或CI/CD环境复现:pip freeze > requirements.txt。下次在新环境只需pip install -r requirements.txt即可。

2.2 项目目录结构设计

一个清晰的目录结构是维护大型测试套件的基石。杂乱无章的文件堆砌会迅速让项目陷入泥潭。我推荐以下结构,它遵循了pytest的约定,并引入了分层思想:

api_test_with_pytest/ ├── requirements.txt # 项目依赖清单 ├── conftest.py # pytest的全局配置文件,用于定义fixture和钩子 ├── pytest.ini # pytest的配置文件,用于定义默认运行规则 ├── common/ # 公共模块目录 │ ├── __init__.py │ ├── logger.py # 日志记录模块 │ └── request_client.py # 封装的requests客户端,处理鉴权、公共头等 ├── test_data/ # 测试数据目录(可JSON/YAML) │ └── user_data.json ├── test_cases/ # 测试用例目录 │ ├── __init__.py │ ├── test_user_api.py # 用户相关接口测试用例 │ └── test_product_api.py # 商品相关接口测试用例 └── reports/ # 测试报告输出目录(由pytest-html生成)

为什么这么设计?

  • conftest.py: 这是pytest的魔力文件之一。在这里定义的fixture(夹具)可以被任何子目录下的测试文件自动发现和使用,非常适合放置那些需要被多个测试用例共享的配置,比如初始化一个数据库连接、创建一个WebDriver实例,或者对我们而言,创建一个配置好基础URL和请求头的HTTP会话。
  • common/目录:将公共代码(如日志、工具函数、客户端封装)抽离出来,避免重复代码,遵循DRY(Don‘t Repeat Yourself)原则。封装的request_client可以统一处理异常、重试、日志记录和响应断言。
  • 按业务模块(user,product)组织测试用例文件,而不是按技术类型(test_get.py,test_post.py),这样更符合业务视角,查找和维护都更方便。
  • 单独的test_data目录管理数据,实现数据与脚本的分离。当测试数据变化时,无需修改代码。

3. 核心代码实现与pytest特性应用

3.1 封装可复用的请求客户端 (common/request_client.py)

直接在每个测试用例里写requests.get()、requests.post()是初学者的做法,它会导致大量重复代码,且一旦请求逻辑需要调整(比如增加一个通用的请求头),就需要修改无数个文件。我们需要一个封装良好的客户端。

# common/request_client.py import requests import logging from typing import Optional, Dict, Any class RequestClient: """封装requests库,提供统一的接口请求方法,并集成日志和基础断言。""" def __init__(self, base_url: str, default_headers: Optional[Dict] = None): self.base_url = base_url.rstrip('/') # 去除末尾可能存在的斜杠 self.session = requests.Session() if default_headers: self.session.headers.update(default_headers) self.logger = logging.getLogger(__name__) def _send_request(self, method: str, endpoint: str, **kwargs) -> requests.Response: """内部方法,统一处理请求发送和日志记录。""" url = f"{self.base_url}/{endpoint.lstrip('/')}" self.logger.info(f"发送请求: {method.upper()} {url}") if 'json' in kwargs: self.logger.debug(f"请求体: {kwargs['json']}") if 'params' in kwargs: self.logger.debug(f"查询参数: {kwargs['params']}") try: response = self.session.request(method, url, **kwargs) self.logger.info(f"收到响应: 状态码={response.status_code}, 耗时={response.elapsed.total_seconds():.2f}s") self.logger.debug(f"响应体: {response.text[:500]}...") # 只记录前500字符,避免日志过长 return response except requests.exceptions.RequestException as e: self.logger.error(f"请求发生异常: {e}") raise # 将异常向上抛出,由测试用例处理 # 提供便捷的HTTP方法封装 def get(self, endpoint: str, **kwargs) -> requests.Response: return self._send_request('GET', endpoint, **kwargs) def post(self, endpoint: str, **kwargs) -> requests.Response: return self._send_request('POST', endpoint, **kwargs) def put(self, endpoint: str, **kwargs) -> requests.Response: return self._send_request('PUT', endpoint, **kwargs) def delete(self, endpoint: str, **kwargs) -> requests.Response: return self._send_request('DELETE', endpoint, **kwargs) # 一个简单的响应断言辅助方法 @staticmethod def assert_response(response: requests.Response, expected_status_code: int = 200, expected_fields: Optional[Dict[str, Any]] = None): """断言响应状态码和关键字段。""" assert response.status_code == expected_status_code, \ f"状态码断言失败!期望{expected_status_code},实际{response.status_code}。响应体:{response.text}" if expected_fields and response.headers.get('Content-Type', '').startswith('application/json'): resp_json = response.json() for field, expected_value in expected_fields.items(): actual_value = resp_json.get(field) assert actual_value == expected_value, \ f"字段'{field}'断言失败!期望{expected_value},实际{actual_value}。"

封装的好处:

  1. 统一入口:所有请求都通过RequestClient发出,便于集中管理超时、重试、代理等设置。
  2. 会话保持:使用requests.Session()可以自动保持cookies,模拟浏览器行为,对于需要登录态的接口测试至关重要。
  3. 日志集成:每个请求和响应的关键信息都被自动记录,调试时一目了然。
  4. 简化断言:提供了assert_response静态方法,虽然简单,但封装了常见的断言逻辑,让测试用例更简洁。

3.2 定义全局Fixture (conftest.py)

fixture是pytest的灵魂,它提供了依赖注入机制。我们可以把RequestClient的实例化、测试数据的读取、甚至清理工作都做成fixture。

# conftest.py import pytest import json import os from common.request_client import RequestClient # 从环境变量或配置文件读取基础URL,提高灵活性 BASE_URL = os.getenv('API_BASE_URL', 'https://api.example.com/v1') DEFAULT_HEADERS = { 'Content-Type': 'application/json', 'User-Agent': 'Pytest-API-Test/1.0' } @pytest.fixture(scope="session") def api_client(): """创建一个全局的API客户端,整个测试会话只初始化一次。""" client = RequestClient(base_url=BASE_URL, default_headers=DEFAULT_HEADERS) yield client # yield之前是setup,之后是teardown # 如果需要,可以在这里进行会话级别的清理,比如登出 # client.post('/logout') print("\n所有测试执行完毕,API客户端会话结束。") @pytest.fixture def auth_client(api_client): """一个需要认证的客户端fixture。它依赖于api_client,并自动完成登录。""" # 假设登录接口返回一个token login_data = {"username": "test_user", "password": "test_pass123"} resp = api_client.post('/auth/login', json=login_data) token = resp.json().get('access_token') # 将token添加到请求头中 auth_headers = {'Authorization': f'Bearer {token}'} api_client.session.headers.update(auth_headers) yield api_client # 返回已携带认证信息的客户端 # 测试函数执行后,可以清理认证头(可选) api_client.session.headers.pop('Authorization', None) @pytest.fixture def user_test_data(): """加载用户相关的测试数据。""" data_path = os.path.join(os.path.dirname(__file__), 'test_data', 'user_data.json') with open(data_path, 'r', encoding='utf-8') as f: return json.load(f)

关键点解析:

  • scope="session":这个fixture在整个pytest执行过程中只会创建一次,并被所有测试用例共享。这对于创建数据库连接、HTTP会话(Session)非常高效。
  • yield:这是fixture定义中用于分隔“设置”和“清理”代码的关键字。yield之前的代码在测试用例执行前运行,yield返回的值(这里是client)会注入到测试用例中。测试用例执行后,会继续执行yield之后的清理代码。
  • 依赖注入:auth_client这个fixture的参数列表中包含了api_client,这意味着pytest会先执行api_client这个fixture,并将其返回值作为参数传递给auth_client。这种链式依赖让代码组织非常清晰。
  • 数据驱动:user_test_data这个fixture负责从外部文件加载数据,实现了测试逻辑与测试数据的分离。

3.3 编写第一个pytest测试用例 (test_cases/test_user_api.py)

有了强大的fixture,编写测试用例就变得异常简洁和聚焦。

# test_cases/test_user_api.py import pytest class TestUserAPI: """用户相关接口的测试类。使用类可以更好地组织相关测试方法。""" def test_get_user_list(self, api_client, user_test_data): """测试获取用户列表接口。""" # 从fixture注入依赖 client = api_client test_data = user_test_data.get('get_user_list', {}) # 发起请求 params = test_data.get('params', {}) response = client.get('/users', params=params) # 使用封装的断言方法 client.assert_response(response, expected_status_code=200, expected_fields={'success': True}) # 也可以使用pytest原生的assert进行更灵活的断言 resp_json = response.json() assert 'data' in resp_json assert isinstance(resp_json['data'], list) # 断言列表长度或特定用户信息 # assert len(resp_json['data']) > 0 # assert resp_json['data'][0]['username'] == 'admin' def test_create_user(self, api_client, user_test_data): """测试创建用户接口。""" client = api_client test_data = user_test_data.get('create_user', {}) payload = test_data['payload'] response = client.post('/users', json=payload) client.assert_response(response, expected_status_code=201) # 201 Created resp_json = response.json() # 断言返回的数据包含我们提交的数据 assert resp_json['data']['username'] == payload['username'] assert resp_json['data']['email'] == payload['email'] # 通常创建成功后,会返回一个用户ID,可以保存下来供后续测试使用 created_user_id = resp_json['data']['id'] # 我们可以将其存储起来,例如存到fixture或一个全局缓存中(需注意测试隔离) @pytest.mark.parametrize("user_id, expected_status", [(1, 200), (99999, 404), ('invalid', 400)]) def test_get_user_by_id(self, api_client, user_id, expected_status): """参数化测试:测试获取不同ID用户的接口响应。""" response = api_client.get(f'/users/{user_id}') assert response.status_code == expected_status if expected_status == 200: assert response.json()['data']['id'] == user_id def test_update_user_with_auth(self, auth_client, user_test_data): """测试需要认证的更新用户接口。使用auth_client fixture。""" # auth_client 已经是一个携带了认证token的客户端 client = auth_client test_data = user_test_data.get('update_user', {}) user_id = test_data['user_id'] update_payload = test_data['payload'] response = client.put(f'/users/{user_id}', json=update_payload) client.assert_response(response, expected_status_code=200) # 验证更新是否生效 get_resp = client.get(f'/users/{user_id}') assert get_resp.json()['data']['email'] == update_payload['email']

用例设计要点:

  1. 测试类:将同一模块(如UserAPI)的测试用例组织在一个类中,比散落的函数更清晰。类名以Test开头,pytest会自动发现。
  2. 测试方法:方法名以test_开头。方法应该职责单一,只测试一个具体的功能点。
  3. 依赖注入:测试方法的参数就是它需要的fixture。pytest会自动查找并注入对应的值。test_update_user_with_auth需要认证,所以它请求auth_client而不是api_client。
  4. 参数化测试 (@pytest.mark.parametrize):这是pytest的杀手锏之一。它允许你用多组数据运行同一个测试逻辑。上面的例子用三组数据(有效ID、不存在ID、非法ID)测试了GET /users/{id}接口,避免了写三个几乎相同的方法。
  5. 断言:使用Python原生的assert语句。pytest会对其进行增强,在断言失败时提供非常详细的上下文信息(比如变量的值),这比unittest的self.assertEqual更直观。我们封装的assert_response内部也使用了assert。

3.4 分离测试数据 (test_data/user_data.json)

将测试数据从代码中剥离,是提升测试可维护性的关键一步。

{ "get_user_list": { "description": "获取用户列表的测试数据", "params": { "page": 1, "limit": 10, "active": true } }, "create_user": { "description": "创建新用户的测试数据", "payload": { "username": "pytest_user_001", "password": "SecurePass123!", "email": "pytest.user@example.com", "role": "member" } }, "update_user": { "description": "更新用户信息的测试数据", "user_id": 1001, "payload": { "email": "updated.email@example.com", "phone": "13800138000" } } }

数据管理心得:

  • 结构化:使用JSON或YAML等格式,可以清晰地组织多层数据。
  • 描述性:为每份数据添加description字段,方便理解其用途。
  • 可扩展:当需要测试边界值、异常数据时,只需在JSON文件中添加新的数据组,然后在测试用例中使用参数化来读取它们,无需改动代码。
  • 环境差异:对于不同环境(测试、预生产)可能需要不同的数据(如域名、测试账号),可以考虑使用不同的数据文件,并通过pytest命令行参数或环境变量来指定加载哪一个。

4. 运行测试与生成报告

4.1 配置pytest运行选项 (pytest.ini)

在项目根目录创建pytest.ini文件,可以预设pytest的运行参数,避免每次都在命令行输入一长串。

# pytest.ini [pytest] # 指定测试文件的搜索路径 testpaths = test_cases # 自动发现以 test_ 开头或 _test 结尾的文件和类/方法 python_files = test_*.py python_classes = Test* python_functions = test_* # 增加详细输出,显示每个测试用例的名字和结果 addopts = -v # 当测试失败时,显示局部变量值,方便调试 addopts = --tb=short # 如果希望测试失败后立即停止,可以加上 -x # addopts = -v --tb=short -x

4.2 执行测试并生成HTML报告

配置好pytest.ini后,在项目根目录下执行最简单的命令即可运行所有测试:

pytest

如果要运行特定文件、类或方法:

pytest test_cases/test_user_api.py # 运行一个文件 pytest test_cases/test_user_api.py::TestUserAPI # 运行一个测试类 pytest test_cases/test_user_api.py::TestUserAPI::test_create_user # 运行一个测试方法 pytest -k "create or update" # 运行名称中包含'create'或'update'的测试

生成HTML报告是我们安装pytest-html的目的。运行以下命令:

pytest --html=reports/report.html --self-contained-html
  • --html=reports/report.html:指定HTML报告的输出路径。
  • --self-contained-html:这个选项会将CSS样式内联到HTML文件中,生成一个独立的文件,分享时不需要附带其他样式文件,非常方便。

打开生成的report.html,你会看到一个包含总览、结果详情、通过/失败/跳过/错误统计、甚至控制台输出的完整报告。这对于在每日构建、持续集成中查看测试结果,或者向非技术同事展示测试覆盖率,都极具价值。

4.3 集成日志系统 (common/logger.py)

控制台输出和HTML报告虽然好,但对于长期运行的自动化任务,一个文件化的日志系统必不可少。

# common/logger.py import logging import sys from pathlib import Path def setup_logger(name: str, log_file: str = 'logs/test_run.log', level=logging.INFO): """设置并返回一个logger实例。""" # 创建日志目录 log_path = Path(log_file) log_path.parent.mkdir(parents=True, exist_ok=True) # 创建logger logger = logging.getLogger(name) logger.setLevel(level) # 避免重复添加handler(防止在多次导入时创建重复的handler) if logger.handlers: return logger # 创建formatter formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s' ) # 文件handler file_handler = logging.FileHandler(log_file, encoding='utf-8') file_handler.setFormatter(formatter) logger.addHandler(file_handler) # 控制台handler (可选,因为pytest自己会捕获输出) console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter(formatter) logger.addHandler(console_handler) return logger # 在conftest.py或测试开始时初始化一个全局logger # logger = setup_logger(__name__)

然后在你的RequestClient或conftest.py中使用这个logger,所有请求、响应和自定义的调试信息都会被同时记录到文件和控制台,便于事后追溯和分析。

5. 高级技巧与实战避坑指南

5.1 测试前置与后置的精细化控制

pytest的fixture提供了不同作用域(function,class,module,session)来控制其生命周期。理解并正确使用它们对测试效率和资源管理很重要。

  • scope=”function”(默认):每个测试函数都会运行一次fixture的setup和teardown。适用于需要完全隔离的测试,比如每个测试都要创建一个全新的临时文件。
  • scope=”class”:同一个测试类中的所有方法共享一次fixture。如果类中的多个测试方法都需要同一个昂贵的初始化操作(如启动一个本地服务),用这个可以节省时间。
  • scope=”module”:同一个.py文件中的所有测试函数共享一次fixture。
  • scope=”session”:整个测试会话只执行一次。我们的api_client就用了这个,因为创建一个HTTP会话是轻量级且可以共享的。

一个常见的坑:在session作用域的fixture里修改了可变对象(比如一个字典或列表),并且这个对象被多个测试用例使用。这会导致测试用例之间的状态污染,测试结果变得不可预测。解决方案:要么使用function作用域确保隔离,要么在fixture中返回数据的深拷贝(copy.deepcopy),要么确保每个测试用例只读不写共享数据。

5.2 处理异步接口与超时

现代API很多是异步的,即请求立即返回一个“任务ID”,你需要轮询另一个接口来获取结果。测试这类接口需要不同的策略。

import time import pytest def test_async_task(api_client): """测试一个异步创建报告的任务。""" # 1. 触发异步任务 trigger_resp = api_client.post('/reports/generate', json={'type': 'daily'}) assert trigger_resp.status_code == 202 # 202 Accepted 是常见的异步接受状态码 task_id = trigger_resp.json().get('task_id') assert task_id is not None # 2. 轮询查询任务状态 max_retries = 10 poll_interval = 3 # 秒 for i in range(max_retries): time.sleep(poll_interval) status_resp = api_client.get(f'/tasks/{task_id}') status = status_resp.json().get('status') if status == 'SUCCESS': report_url = status_resp.json().get('report_url') # 进一步验证报告内容... assert report_url is not None break elif status == 'FAILED': pytest.fail(f"异步任务执行失败: {status_resp.json().get('error_message')}") # 如果状态是PENDING或RUNNING,则继续循环 else: # 循环正常结束(非break跳出),说明超时 pytest.fail(f"异步任务未在{max_retries * poll_interval}秒内完成")

注意事项:

  • 设置合理的超时和重试次数:避免测试因网络抖动或服务暂时繁忙而失败,但也要防止无限等待。
  • 使用pytest.fail明确失败:在轮询逻辑中,如果任务失败或超时,使用pytest.fail可以给出清晰的失败信息,而不是一个模糊的超时异常。

5.3 使用Mock进行依赖隔离

在测试某个接口时,如果它强依赖于另一个不稳定或未开发完成的外部服务(比如第三方支付网关、短信服务),直接调用会导致测试不可靠。这时可以使用pytest-mock插件(或标准库unittest.mock)来模拟(Mock)这些依赖。

pip install pytest-mock
# test_cases/test_payment_api.py import pytest def test_create_order_with_mocked_payment(api_client, mocker): # mocker是pytest-mock提供的fixture """测试创建订单,但模拟支付网关的调用。""" # 假设我们的服务在创建订单后会调用一个外部支付网关 # 1. 模拟(Mock)掉那个支付网关的客户端函数或类 # 假设我们在 `service.payment_gateway` 模块里有一个 `charge` 函数 mock_charge = mocker.patch('service.payment_gateway.charge') # 设置这个模拟函数的返回值,让它模拟支付成功 mock_charge.return_value = {'success': True, 'transaction_id': 'mock_tx_12345'} # 2. 正常调用我们的创建订单接口 order_data = {"product_id": 101, "amount": 99.9} response = api_client.post('/orders', json=order_data) # 3. 断言我们的接口逻辑正确 assert response.status_code == 201 assert response.json()['data']['status'] == 'paid' # 因为支付被模拟成功了 # 4. 断言我们的模拟函数被以预期的参数调用了(可选,用于验证流程) mock_charge.assert_called_once() # 可以进一步断言调用参数 # mock_charge.assert_called_with(amount=99.9, currency='CNY')

Mock的核心价值:它允许你将测试焦点完全集中在当前被测接口的逻辑上,排除外部依赖的干扰,使得测试更快、更稳定、更专注。这在单元测试和集成测试中都非常有用。

5.4 常见问题排查与调试技巧

  1. Fixture找不到或注入失败:

    • 检查conftest.py位置:fixture定义在哪个conftest.py中,就只能在同级及下级目录的测试文件中使用。通常放在项目根目录的conftest.py里最省事。
    • 检查作用域:一个function作用域的fixture不能被一个session作用域的fixture依赖(因为生命周期更短)。
    • 使用pytest --setup-show test_file.py:这个命令可以显示测试用例执行过程中fixture的setup和teardown顺序,是排查依赖问题的利器。
  2. 测试用例顺序依赖导致失败:

    • pytest默认会打乱测试用例的执行顺序以避免依赖。如果你的测试用例之间有状态依赖(比如A用例创建的数据,B用例依赖),这就是一个坏的测试实践。
    • 强制解决(不推荐):可以用pytest-ordering插件标记顺序,但这只是掩盖问题。
    • 根本解决:每个测试用例都应该是独立的。使用fixture在用例开始前创建所需状态,在用例结束后清理。对于需要共享的只读数据(如配置),使用session作用域的fixture。
  3. HTML报告没有生成或样式丢失:

    • 确保命令中指定了正确的路径,且目录有写入权限。
    • 使用--self-contained-html生成独立文件。
    • 如果报告内容不全,检查是否因为测试失败导致pytest提前退出(用了-x参数)。可以去掉-x再运行。
  4. 如何调试一个失败的测试:

    • pytest -vvs:-s参数禁止pytest捕获控制台输出,让你能在测试中直接使用print或logging调试。-vv显示更详细信息。
    • 在IDE中调试:在测试方法上打上断点,像调试普通Python程序一样调试。这是最强大的方式。
    • 分析失败断言:pytest的断言失败信息通常非常详细,会显示表达式中各个部分的值。仔细阅读它,往往能直接找到问题根源。

从写零散的请求脚本,到构建一个结构清晰、可维护、可扩展、具备专业报告能力的pytest接口测试框架,这个过程带来的效率提升和信心增强是巨大的。最关键的一步是开始实践,从一个小模块开始,逐步应用fixture、参数化、封装和Mock这些特性,你会发现自己对接口测试和Python自动化测试的理解越来越深。

相关新闻

  • AI生成内容的版权归属:法律边界与技术实践
  • Pytest命令行传参与参数化测试实战:提升自动化测试灵活性与效率
  • AI Agent 运行时架构:从 Context 陷阱到事件日志驱动的稳定执行

最新新闻

  • 自适应Transformer架构AdaPerceiver的设计与实践
  • 基于代理模式的服务发现与治理:Agency-Agents实战指南
  • 告别文件格式烦恼:UniExtract2如何成为你的终极解压瑞士军刀
  • 基于Grounding-DINO、SAM2和GPT4o的动态对象分割技术
  • 太赫兹傅里叶叠层成像技术突破衍射极限
  • 网络安全学习130天

日新闻

  • 【计算机毕业设计案例】基于 Spring Boot+Vue 的电影售票系统设计与实现 前后端分离架构下影院在线购票管理平台(程序+文档+讲解+定制)
  • 到底 TMD 用哪个: npm, pnpm, Yarn, Bun, Deno? 傻瓜, 当然用 npm 啦
  • Google限制Meta使用Gemini模型 凸显AI授权竞争白热化

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

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

服务项目

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

快速链接

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

联系方式

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

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