graphql-to-httprunner


Namegraphql-to-httprunner JSON
Version 1.9.2 PyPI version JSON
download
home_pageNone
SummaryAutomatically generate HttpRunner test cases based on GraphQL Schema
upload_time2025-08-05 08:44:07
maintainerNone
docs_urlNone
authorDevin
requires_python>=3.5
licenseMIT
keywords graphql httprunner api automation test
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # GraphQL to HttpRunner

[graphql-to-httprunner](https://pypi.org/project/graphql-to-httprunner),一个基于GraphQL Schema自动生成HttpRunner测试用例的自动化工具。

## 一、主要功能
1. 支持直接解析GraphQL Schema文件,提取查询操作和类型定义
2. 支持通过内省查询(Introspection Query)自动获取GraphQL Schema
3. 支持为每个查询操作生成对应的HttpRunner测试用例
4. 自动构建GraphQL查询语句,包括字段选择、参数处理、以及默认值生成
5. 自动化生成合适的通用测试断言
6. 一键直接生成GraphQL查询语句列表,方便开发调试
7. 支持API层和用例层测试用例生成,满足HttpRunner分层测试需求
8. 支持测试用例生成时选择全量参数或仅必选参数
9. 支持测试用例生成时是否包含skip关键字,方便用例执行
10. 支持多项目批处理模式、单项目处理模式、单个查询处理模式
11. 支持生成GraphQL查询语句时自动备份和差异对比,方便追踪API变更
12. 支持根据GraphQL查询语句差异报告自动更新测试用例,提升维护效率

## 二、代码结构
项目采用模块化设计,主要包含以下文件:

### 核心模块
- `graphql_to_httprunner/models.py`: 数据模型模块,定义了GraphQL Schema的核心数据结构
  - `GraphQLType`: 表示GraphQL类型,包含字段和实现接口信息
  - `GraphQLSchema`: 表示整个Schema,包含类型、接口和根字段

- `graphql_to_httprunner/parser.py`: 解析器模块,负责解析GraphQL Schema文件
  - `GraphQLSchemaParser`: 解析GraphQL Schema的内容,提取类型、接口、枚举等信息

- `graphql_to_httprunner/introspection.py`: 内省查询模块,通过内省查询获取GraphQL Schema
  - `fetch_schema_from_introspection`: 向GraphQL服务发送内省查询请求,获取Schema

- `graphql_to_httprunner/generator.py`: 生成器模块,负责生成HttpRunner测试用例
  - `HttpRunnerTestCaseGenerator`: 根据Schema生成HttpRunner YAML测试用例,同时支持生成API层和用例层测试用例

- `graphql_to_httprunner/query_generator.py`: 查询语句生成器模块,负责生成GraphQL查询语句列表
  - `GraphQLQueryGenerator`: 根据Schema生成GraphQL查询语句

- `graphql_to_httprunner/report_generator.py`: 查询语句文件差异报告生成模块,用于在GraphQL Schema发生变更时生成详细的差异比较报告
  - `generate_markdown_diff_report`: Markdown格式的差异报告生成
  - `generate_html_diff_report`: HTML格式的差异报告生成

### 工具模块
- `graphql_to_httprunner/main.py`: 程序入口模块,提供命令行界面,协调调用解析器和生成器
- `graphql_to_httprunner/utils.py`: 工具类模块,提供文件备份和差异比较等通用功能
  - `backup_queries_file`: 备份查询语句文件
  - `compare_query_files`: 比较新旧查询语句文件的差异并生成报告
- `graphql_to_httprunner/__main__.py`: 包根目录入口点,允许直接模块运行
- `graphql_to_httprunner/__init__.py`: 包初始化文件,提供模块导入接口
- `__main__.py`: 项目根目录入口点,允许直接运行项目

### 项目结构
```
graphql-schema-to-httprunner/
├── graphql_to_httprunner/        # 主包目录
│   ├── __main__.py               # 主包目录入口点
│   ├── __init__.py               # 包初始化文件
│   ├── models.py                 # 数据模型模块
│   ├── parser.py                 # 解析器模块
│   ├── introspection.py          # 内省查询模块
│   ├── generator.py              # 生成器模块
│   ├── query_generator.py        # 查询语句生成器模块
│   ├── report_generator.py       # 查询语句文件差异报告生成器模块
│   ├── utils.py                  # 工具函数模块
│   └── main.py                   # 命令行入口模块
├── tests/                        # 单元测试目录
├── __main__.py                   # 项目根目录入口点
├── pyproject.toml                # 项目配置文件
├── setup.py                      # 兼容旧式安装的配置文件
├── MANIFEST.in                   # 指定打包时要包含和排查的文件
└── README.md                     # 项目说明文档
```

## 三、安装方法

### 3.1 使用pip安装(推荐)
```bash
# 从PIPY仓库安装
pip install graphql-to-httprunner

# 或者从Git仓库安装
pip install git+https://git.umlife.net/zhangchuzhao/graphql-schema-to-httprunner.git
```

### 3.2 开发模式安装
```bash
# 从本地源码安装
pip install .

# 使用pip开发模式安装
pip install -e .

# 或者使用poetry安装
poetry install
```

## 四、使用方法

### 4.1 命令行使用(推荐)

安装后可以直接使用`gpl2hrun`或`gpl2case`或`graphql2httprunner`或`graphql2testcase`命令:

```bash
# 基于schema.graphql文件生成HttpRunner用例层测试用例
gpl2hrun -f schema.graphql -t -o testcases -u http://your-api-url -d 2

# 基于内省查询URL生成HttpRunner用例层测试用例
gpl2hrun -i http://your-graphql-server/graphql -t -o testcases -u http://your-api-url -d 2

# 基于schema.graphql文件生成HttpRunner API层测试用例
gpl2hrun -f schema.graphql -t --api -o api -u http://your-api-url -d 2

# 基于内省查询URL生成HttpRunner API层测试用例
gpl2hrun -i http://your-graphql-server/graphql -t --api -o api -u project_name -d 2

# 基于schema.graphql文件生成HttpRunner用例层测试用例(仅包含必选参数)
gpl2hrun -f schema.graphql -t -o testcases --required

# 基于schema.graphql文件生成HttpRunner API层测试用例(仅包含必选参数)
gpl2hrun -f schema.graphql -t --api -o api --required

# 基于schema.graphql文件生成HttpRunner API层测试用例(包含关键字参数skip)
gpl2hrun -f schema.graphql -t --api -o api --skip

# 基于schema.graphql文件生成HttpRunner API层测试用例,同时生成引用API的测试用例
gpl2hrun -f schema.graphql -t --api -o api --cite

# 基于schema.graphql文件生成GraphQL查询语句
gpl2hrun -f schema.graphql -q

# 基于schema.graphql文件生成GraphQL查询语句,并默认与旧查询语句文件query.yml进行对比生成差异报告(两种格式)
gpl2hrun -f schema.graphql -q --report both

# 基于schema.graphql文件生成GraphQL查询语句,并生成Markdown格式差异报告
gpl2hrun -f schema.graphql -q --report markdown

# 基于schema.graphql文件生成GraphQL查询语句,并生成HTML格式差异报告
gpl2hrun -f schema.graphql -q --report html

# 基于schema.graphql文件生成GraphQL查询语句,并指定项目名查询语句文件分组标识
gpl2hrun -f schema.graphql -q --project project_name

# 基于内省查询URL生成GraphQL查询语句
gpl2hrun -i http://your-graphql-server/graphql -q -o my.yml -u http://your-api-url -d 2

# 基于内省查询URL生成GraphQL查询语句,并与指定与my.yml进行对比生成差异报告(两种格式)
gpl2hrun -i http://your-graphql-server/graphql -q -o my.yml -u http://your-api-url -d 2 --report both

# 基于内省查询URL生成GraphQL查询语句,并生成HTML格式差异报告
gpl2hrun -i http://your-graphql-server/graphql -q -o my.yml -u http://your-api-url -d 2 --report html

# 使用配置文件批量生成多个项目的HttpRunner测试用例
gpl2hrun -b config.csv -t

# 使用配置文件批量生成多个项目的GraphQL查询语句列表,生成路径默认为query.yaml
gpl2hrun -b config.csv -q

# 使用配置文件批量生成多个项目的GraphQL查询语句列表,并默认与旧查询语句文件query.yaml进行对比生成差异报告(两种格式)
gpl2hrun -b config.csv -q --report both

# 使用配置文件批量生成多个项目的GraphQL查询语句列表,并生成Markdown格式差异报告
gpl2hrun -b config.csv -q --report markdown

# 使用配置文件批量生成多个项目的GraphQL查询语句列表,生成路径指定为my_query.yaml
gpl2hrun -b config.csv -q --queries-file my_query.yaml

# 使用配置文件批量生成多个项目的GraphQL查询语句列表,并与指定my_query.yaml进行对比生成差异报告(两种格式)
gpl2hrun -b config.csv -q --queries-file my_query.yaml --report both

# 使用配置文件批量生成多个项目的GraphQL查询语句列表,并生成HTML格式差异报告
gpl2hrun -b config.csv -q --queries-file my_query.yaml --report html

# 根据配置文件和查询语句差异报告自动更新HttpRunner测试用例,查询语句文件默认为query.yaml,并生成默认HTML格式差异报告
gpl2hrun -b config.csv -a

# 根据配置文件和查询语句差异报告自动更新HttpRunner测试用例,查询语句文件默认为query.yaml,并生成Markdown格式差异报告
gpl2hrun -b config.csv -a --report markdown

# 根据配置文件和查询语句差异报告自动更新HttpRunner测试用例,查询语句文件指定为my_query.yaml
gpl2hrun -b config.csv -a --queries-file my_query.yaml

# 基于内省查询URL生成操作名称 xxx 的HttpRunner用例层测试用例
gpl2hrun -i http://localhost:8888/graphql -t --query-name xxx

# 基于内省查询URL生成操作名称 xxx 的查询语句
python . -i http://localhost:8888/graphql -q --project swapi --query-name xxx
```

配置文件格式为CSV,包含以下列:
```
project_name,introspection_url,output,base_url,max_depth,required,api,is_cite,is_skip,offline
swapi,http://localhost:8888/graphql,swapi,http://localhost:8888,2,false,false,false,false,false
youcloud,https://example-youcloud.com/graphql,youcloud,youcloud,5,true,true,false,true,false
project3,https://example-project2.com/graphql,project3,project3,6,true,true,true,true,true
```

- `project_name`: 项目名称,用于标识和日志输出
- `introspection_url`: GraphQL内省查询URL
- `output`: 输出目录路径,批量生成GraphQL查询语句时默认为query.yaml
- `base_url`: GraphQL API基础URL
- `max_depth`: GraphQL查询嵌套的最大深度
- `required`: 是否只包含必选参数,值为"true"或"false"
- `api`: 是否生成API层测试用例,值为"true"或"false"
- `is_cite`: 是否生成引用API层的测试用例,值为"true"或"false"
- `is_skip`: 是否生成测试用例是否包含skip关键词,值为"true"或"false"
- `offline`: 项目是否已下线,值为"true"或"false",批处理时会跳过已下线项目

### 4.2 源码执行使用方式

如果没有通过pip安装,或者需要直接运行源码,可以使用以下方式:

```bash
# 使用根目录的__main__.py入口点(省略模块/指定模块)
python . -f schema.graphql -t -o testcases -u http://your-api-url -d 2
python __main__.py -f schema.graphql -t -o testcases -u http://your-api-url -d 2

# 使用包目录__main__.py入口点
python -m graphql_to_httprunner -f schema.graphql -t -o testcases -u http://your-api-url -d 2

# 使用graphql_to_httprunner/main.py入口点
python -m graphql_to_httprunner.main -f schema.graphql -t -o testcases -u http://your-api-url -d 2
```

### 4.3 代码模块使用方式

```python
from graphql_to_httprunner.parser import GraphQLSchemaParser
from graphql_to_httprunner.generator import HttpRunnerTestCaseGenerator

# 解析GraphQL Schema文件
with open('schema.graphql', 'r') as f:
    schema_content = f.read()
    
parser = GraphQLSchemaParser(schema_content)
schema = parser.parse()

# 生成测试用例
generator = HttpRunnerTestCaseGenerator(schema, base_url="http://your-api-url")
testcase_count = generator.generate_test_cases("testcases")
print(f"已生成{testcase_count}个测试用例")
```

### 4.4 参数说明
```bash
gpl2hrun -h

usage: gpl2hrun [-h] [-V] [-b BATCH] [-f SCHEMA_FILE | -i INTROSPECTION_URL] [-t | -q] [-o OUTPUT] [-u BASE_URL] [-d MAX_DEPTH] [--api] [--required] [-a] [--queries-file QUERIES_FILE]

将GraphQL Schema转换为HttpRunner测试用例或查询语句

optional arguments:
  -h, --help
  -V, --version
  -b BATCH, --batch BATCH
  -f SCHEMA_FILE, --schema-file SCHEMA_FILE
  -i INTROSPECTION_URL, --introspection-url INTROSPECTION_URL
  -t, --testcases
  -q, --queries
  -o OUTPUT, --output OUTPUT
  -u BASE_URL, --base-url BASE_URL
  -d MAX_DEPTH, --max-depth MAX_DEPTH
  --api
  --cite
  --required
  --skip
  --report {markdown,html,both}
  --project
  -a, --auto-update
  --queries-file QUERIES_FILE
  --query-name QUERY_NAME
```

- `-b, --batch`: 批量处理配置文件路径,如 config.csv
- `-f, --schema-file`: GraphQL Schema文件路径
- `-i, --introspection-url`: GraphQL内省查询URL,如 http://localhost:9527/graphql
- `-t, --testcases`: 生成HttpRunner测试用例
- `-q, --queries`: 生成GraphQL查询语句列表
- `--api`: 生成API层测试用例而非用例层测试用例(仅当使用 `-t` 时有效)
- `--cite`: 生成引用API层测试用例(与--api选项一起使用)
- `--required`: 只包含必选参数,默认情况下包含所有参数(仅当使用 `-t` 时有效)
- `--skip`: 生成的测试用例是否包含skip关键词(仅当使用 `-t` 时有效)
- `--report`: 生成差异报告格式(与-q选项一起使用),可选值:`markdown`、`html`、`both`。单项目模式默认与query.yaml对比或通过-o参数指定,批处理模式默认与query.yaml对比或通过--queries-file参数指定
- `-o, --output`: 生成结果输出路径,根据生成类型默认为api、testcases、query.yml三种情况(注意:批模式生成Graphql查询语句时默认为query.yaml,以便适配现有脚本引用方式)
- `-u, --base-url`: API基础URL或项目名,项目名用来作为自定义函数参数生成API基础URL,默认为'http://localhost:8888'
- `-d, --max-depth`: GraphQL查询嵌套的最大深度,默认为2
- `--project`: 指定项目名称,作为生成查询语句文件分组标识,默认为project_name
- `-a, --auto-update`: 根据GraphQL查询语句差异报告自动更新测试用例(需与 `-b` 一起使用)
- `--queries-file`: 查询语句文件输出或获取路径,默认为query.yaml (与-b选项一起使用)
- `--query-name`: 指定要生成的单个查询名称,只生成该查询的测试用例或查询语句

> 注意:
> - 当指定 `-b/--batch` 参数时,工具将进入批处理模式,从配置文件中读取多个项目信息进行批量处理
> - 批处理模式下,可以同时指定 `-t/--testcases` 或 `-q/--queries` 选项来指定生成测试用例或查询语句
> - 单个项目模式下(不使用 `-b/--batch`),必须指定 `-f/--schema-file` 或 `-i/--introspection-url` 选项,且必须指定 `-t/--testcases` 或 `-q/--queries` 选项
> - `-f` 和 `-i` 是互斥参数,只能二选一使用
> - `-t` 和 `-q` 是互斥参数,只能二选一使用
> - 如果使用 `-t` 选项,则 `-o` 参数指定输出目录;如果使用 `-q` 选项,则 `-o` 参数指定输出文件路径
> - `--api` 参数仅在 `-t` 参数存在时有效,用于指定生成API层测试用例
> - `--cite` 参数仅在 `-t`和`--api` 参数存在时有效,用于指定生成引用API层测试用例
> - `--required` 参数仅在 `-t` 参数存在时有效,用于指定只包含必选参数
> - `--skip` 参数仅在 `-t` 参数存在时有效,用于指定生成的测试用例是否包含skip关键词
> - `--report` 参数仅在 `-q` 或 `-a` 参数存在时有效,用于指定差异报告格式:`markdown`(只生成Markdown格式)、`html`(只生成HTML格式)、`both`(同时生成两种格式)

### 4.5 执行HttpRunner测试用例
```bash
# 运行用例层测试用例
hrun testcases
# 运行API层测试用例
hrun api
```

### 4.6 打包上传PyPI
```bash
# 打标签(轻量或附注)
git tag v1.0.0 或 git tag -a v1.0.0 -m "发布正式版本 v1.0.0"
# 推送标签(单个或所有)
git push v1.0.0 或 git push --tags
# 本地配置pyproject.toml和pypi token信息
poetry config pypi-token xxx
# 编译打包(更新__init__.py和pyproject.toml中版本号, poetry publish --build)
poetry build
# 上传发布
poetry publish
```


## 五、注意事项
1. 测试用例中使用$$来转义$符号,以避免与HttpRunner变量语法冲突;
2. HttpRunner接口响应内容引用变量约定为content;
3. 内省查询需要目标GraphQL服务支持标准的内省查询API;
4. 内省查询URL与基础URL不同,分别使用 `-i` 和 `-u` 参数指定;
5. 生成的查询语句列表以YAML格式存储,键为操作名称,值为对应的查询语句;

## 六、查询语句备份与差异对比功能

### 6.1 自动备份功能
当用户执行生成GraphQL查询语句列表任务(使用`-q`参数)时,工具会自动检查是否存在旧的查询语句文件。如果存在,将自动执行以下操作:

1. 将旧文件备份为带时间戳的文件,格式为`文件名.bak.时间戳.扩展名`(例如:`query.yml.bak.20240501123456.yml`)
2. 删除旧的查询语句文件
3. 生成新的查询语句文件
4. 自动执行新旧文件差异对比

这种自动备份机制适用于单项目模式和批处理模式:
- 单项目模式下,备份指定的输出文件,默认为`query.yml`
- 批处理模式下,备份默认`query.yaml`文件

### 6.2 差异对比报告
差异对比功能会自动分析新旧查询语句文件的差异,并根据指定的格式生成详细的报告。支持三种报告格式:

- `markdown`:只生成Markdown格式报告
- `html`:只生成HTML格式报告
- `both`:同时生成Markdown和HTML格式报告(默认行为)

报告包含以下信息:

1. **项目级变更**:新增项目、移除项目
2. **查询级变更**:针对每个修改的项目,详细列出新增查询、移除查询和修改查询
3. **详细差异**:对于修改的查询,提供旧值、新值以及详细的文本差异对比

差异报告文件格式为`文件名.时间戳.diff.md`(例如:`query.yml.20240501123456.diff.md`)和`文件名.时间戳.diff.html`(例如:`query.yml.20240501123456.diff.html`)。

### 6.3 差异对比示例

下面是一个Markdown格式差异报告的示例片段:

````markdown
# GraphQL API 变更监测报告
## 旧文件: query.yaml.bak.20240501123456.yaml
## 新文件: query.yaml

## 新增项目
- project_new

## 修改项目
### youcloud
#### 新增查询
- getNewFeature
  ```
  query getNewFeature {
    newFeature {
      id
      name
    }
  }
  ```

#### 修改查询
- getUserInfo
  旧:
  ```
  query getUserInfo {
    user {
      id
      name
    }
  }
  ```
  新:
  ```
  query getUserInfo {
    user {
      id
      name
      email
    }
  }
  ```
  差异详情:
  ```diff
    query getUserInfo {
      user {
        id
        name
  +     email
      }
    }
  ```
````

通过这个差异报告,用户可以清晰地了解随着API升级和迭代,查询语句发生了哪些变化,便于进行API变更管理和测试用例维护。

### 6.4 工具类模块

为了增强代码的可维护性和模块化,项目将文件备份和差异比较功能抽离到了单独的工具类模块(`utils.py`),主要提供以下功能:

- `backup_queries_file`:负责将现有查询语句文件备份为带时间戳的文件,并删除原文件
- `compare_query_files`:负责比较新旧查询语句文件的差异,并生成详细的Markdown格式差异报告

这些工具函数使项目更加模块化,便于维护和扩展。

## 七、测试用例自动更新功能

随着产品迭代和API变更,GraphQL查询语句会不断更新,导致已生成的HttpRunner测试用例需要手动更新。为了解决这个问题,项目实现了测试用例自动更新功能,能够根据查询语句的差异报告自动更新相应的测试用例文件。

### 7.1 自动更新流程

测试用例自动更新功能的工作流程如下:

1. 备份现有的查询语句文件
2. 根据配置文件重新生成最新的查询语句
3. 比较新旧查询语句文件,生成差异报告
4. 根据差异报告自动处理以下变更:
   - 新增项目:自动生成新项目的所有测试用例
   - 移除项目:自动删除该项目的测试用例目录
   - 修改项目:
     - 新增查询:自动生成新增查询的测试用例
     - 移除查询:自动删除对应的测试用例文件
     - 修改查询:自动更新测试用例中的查询语句

### 7.2 使用方法

使用自动更新功能需要提供配置文件和查询语句文件:

```bash
# 使用默认查询语句文件(query.yaml)
gpl2hrun -b config.csv -a

# 指定查询语句文件
gpl2hrun -b config.csv -a --queries-file custom_queries.yaml
```

### 7.3 注意事项

1. 自动更新功能**必须**与批处理模式(`-b/--batch`)一起使用
2. 配置文件需要包含项目名称、内省查询URL、输出目录等信息
3. 查询语句文件应当包含所有项目的最新查询语句
4. 自动更新过程中如果遇到错误,会尽可能继续处理其他项目和查询
5. 自动更新完成后会输出统计信息,包括新增项目、移除项目、新增查询、移除查询和修改查询的数量
6. 自动更新会保留测试用例中的其他配置和参数值,只更新查询语句部分,不影响已有的自定义配置

### 7.4 工具函数

项目添加了以下工具函数以支持测试用例自动更新功能:

- `find_testcase_files`:查找与指定查询对应的测试用例文件
- `delete_testcase_files`:删除与指定查询对应的测试用例文件
- `update_testcase_query`:更新测试用例文件中的查询语句
- `determine_operation_type`:根据查询语句确定操作类型
- `auto_update_testcases`:根据差异报告自动更新测试用例

通过这些功能,可以大幅提高API测试用例的维护效率,解决GraphQL API变更导致的测试用例失效问题。


## 八、单元测试
项目包含完整的单元测试套件,覆盖所有核心模块功能。

### 8.1 运行测试
```bash
# 安装测试依赖
poetry add -D pytest requests-mock pytest-cov

# 运行所有测试
pytest

# 运行特定模块的测试
pytest tests/test_models.py

# 运行测试并生成覆盖率报告
pytest --cov=graphql_to_httprunner

# 生成HTML格式覆盖率报告
pytest --cov=graphql_to_httprunner --cov-report=html
```
### 8.2 测试文件结构
```
tests/                          # 测试目录
├── conftest.py                # 测试配置文件,定义测试夹具
├── fixtures/                  # 测试数据目录
│   └── schema.graphql        # 测试用的GraphQL Schema
├── test_models.py            # 数据模型测试
├── test_parser.py            # Schema解析器测试
├── test_introspection.py     # 内省查询测试
├── test_generator.py         # 测试用例生成器测试
├── test_query_generator.py   # 查询语句生成器测试
├── test_report_generator.py  # 差异报告生成器测试
└── test_utils.py             # 工具函数测试
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "graphql-to-httprunner",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.5",
    "maintainer_email": null,
    "keywords": "graphql, httprunner, api, automation, test",
    "author": "Devin",
    "author_email": "zhangchuzhao@dingtalk.com",
    "download_url": "https://files.pythonhosted.org/packages/5c/56/bdcd56e9e14a70a29e3a65f085b894eb718df6ed1e124077ae30b22a5888/graphql_to_httprunner-1.9.2.tar.gz",
    "platform": null,
    "description": "# GraphQL to HttpRunner\n\n[graphql-to-httprunner](https://pypi.org/project/graphql-to-httprunner)\uff0c\u4e00\u4e2a\u57fa\u4e8eGraphQL Schema\u81ea\u52a8\u751f\u6210HttpRunner\u6d4b\u8bd5\u7528\u4f8b\u7684\u81ea\u52a8\u5316\u5de5\u5177\u3002\n\n## \u4e00\u3001\u4e3b\u8981\u529f\u80fd\n1. \u652f\u6301\u76f4\u63a5\u89e3\u6790GraphQL Schema\u6587\u4ef6\uff0c\u63d0\u53d6\u67e5\u8be2\u64cd\u4f5c\u548c\u7c7b\u578b\u5b9a\u4e49\n2. \u652f\u6301\u901a\u8fc7\u5185\u7701\u67e5\u8be2(Introspection Query)\u81ea\u52a8\u83b7\u53d6GraphQL Schema\n3. \u652f\u6301\u4e3a\u6bcf\u4e2a\u67e5\u8be2\u64cd\u4f5c\u751f\u6210\u5bf9\u5e94\u7684HttpRunner\u6d4b\u8bd5\u7528\u4f8b\n4. \u81ea\u52a8\u6784\u5efaGraphQL\u67e5\u8be2\u8bed\u53e5\uff0c\u5305\u62ec\u5b57\u6bb5\u9009\u62e9\u3001\u53c2\u6570\u5904\u7406\u3001\u4ee5\u53ca\u9ed8\u8ba4\u503c\u751f\u6210\n5. \u81ea\u52a8\u5316\u751f\u6210\u5408\u9002\u7684\u901a\u7528\u6d4b\u8bd5\u65ad\u8a00\n6. \u4e00\u952e\u76f4\u63a5\u751f\u6210GraphQL\u67e5\u8be2\u8bed\u53e5\u5217\u8868\uff0c\u65b9\u4fbf\u5f00\u53d1\u8c03\u8bd5\n7. \u652f\u6301API\u5c42\u548c\u7528\u4f8b\u5c42\u6d4b\u8bd5\u7528\u4f8b\u751f\u6210\uff0c\u6ee1\u8db3HttpRunner\u5206\u5c42\u6d4b\u8bd5\u9700\u6c42\n8. \u652f\u6301\u6d4b\u8bd5\u7528\u4f8b\u751f\u6210\u65f6\u9009\u62e9\u5168\u91cf\u53c2\u6570\u6216\u4ec5\u5fc5\u9009\u53c2\u6570\n9. \u652f\u6301\u6d4b\u8bd5\u7528\u4f8b\u751f\u6210\u65f6\u662f\u5426\u5305\u542bskip\u5173\u952e\u5b57\uff0c\u65b9\u4fbf\u7528\u4f8b\u6267\u884c\n10. \u652f\u6301\u591a\u9879\u76ee\u6279\u5904\u7406\u6a21\u5f0f\u3001\u5355\u9879\u76ee\u5904\u7406\u6a21\u5f0f\u3001\u5355\u4e2a\u67e5\u8be2\u5904\u7406\u6a21\u5f0f\n11. \u652f\u6301\u751f\u6210GraphQL\u67e5\u8be2\u8bed\u53e5\u65f6\u81ea\u52a8\u5907\u4efd\u548c\u5dee\u5f02\u5bf9\u6bd4\uff0c\u65b9\u4fbf\u8ffd\u8e2aAPI\u53d8\u66f4\n12. \u652f\u6301\u6839\u636eGraphQL\u67e5\u8be2\u8bed\u53e5\u5dee\u5f02\u62a5\u544a\u81ea\u52a8\u66f4\u65b0\u6d4b\u8bd5\u7528\u4f8b\uff0c\u63d0\u5347\u7ef4\u62a4\u6548\u7387\n\n## \u4e8c\u3001\u4ee3\u7801\u7ed3\u6784\n\u9879\u76ee\u91c7\u7528\u6a21\u5757\u5316\u8bbe\u8ba1\uff0c\u4e3b\u8981\u5305\u542b\u4ee5\u4e0b\u6587\u4ef6\uff1a\n\n### \u6838\u5fc3\u6a21\u5757\n- `graphql_to_httprunner/models.py`: \u6570\u636e\u6a21\u578b\u6a21\u5757\uff0c\u5b9a\u4e49\u4e86GraphQL Schema\u7684\u6838\u5fc3\u6570\u636e\u7ed3\u6784\n  - `GraphQLType`: \u8868\u793aGraphQL\u7c7b\u578b\uff0c\u5305\u542b\u5b57\u6bb5\u548c\u5b9e\u73b0\u63a5\u53e3\u4fe1\u606f\n  - `GraphQLSchema`: \u8868\u793a\u6574\u4e2aSchema\uff0c\u5305\u542b\u7c7b\u578b\u3001\u63a5\u53e3\u548c\u6839\u5b57\u6bb5\n\n- `graphql_to_httprunner/parser.py`: \u89e3\u6790\u5668\u6a21\u5757\uff0c\u8d1f\u8d23\u89e3\u6790GraphQL Schema\u6587\u4ef6\n  - `GraphQLSchemaParser`: \u89e3\u6790GraphQL Schema\u7684\u5185\u5bb9\uff0c\u63d0\u53d6\u7c7b\u578b\u3001\u63a5\u53e3\u3001\u679a\u4e3e\u7b49\u4fe1\u606f\n\n- `graphql_to_httprunner/introspection.py`: \u5185\u7701\u67e5\u8be2\u6a21\u5757\uff0c\u901a\u8fc7\u5185\u7701\u67e5\u8be2\u83b7\u53d6GraphQL Schema\n  - `fetch_schema_from_introspection`: \u5411GraphQL\u670d\u52a1\u53d1\u9001\u5185\u7701\u67e5\u8be2\u8bf7\u6c42\uff0c\u83b7\u53d6Schema\n\n- `graphql_to_httprunner/generator.py`: \u751f\u6210\u5668\u6a21\u5757\uff0c\u8d1f\u8d23\u751f\u6210HttpRunner\u6d4b\u8bd5\u7528\u4f8b\n  - `HttpRunnerTestCaseGenerator`: \u6839\u636eSchema\u751f\u6210HttpRunner YAML\u6d4b\u8bd5\u7528\u4f8b\uff0c\u540c\u65f6\u652f\u6301\u751f\u6210API\u5c42\u548c\u7528\u4f8b\u5c42\u6d4b\u8bd5\u7528\u4f8b\n\n- `graphql_to_httprunner/query_generator.py`: \u67e5\u8be2\u8bed\u53e5\u751f\u6210\u5668\u6a21\u5757\uff0c\u8d1f\u8d23\u751f\u6210GraphQL\u67e5\u8be2\u8bed\u53e5\u5217\u8868\n  - `GraphQLQueryGenerator`: \u6839\u636eSchema\u751f\u6210GraphQL\u67e5\u8be2\u8bed\u53e5\n\n- `graphql_to_httprunner/report_generator.py`: \u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\u5dee\u5f02\u62a5\u544a\u751f\u6210\u6a21\u5757\uff0c\u7528\u4e8e\u5728GraphQL Schema\u53d1\u751f\u53d8\u66f4\u65f6\u751f\u6210\u8be6\u7ec6\u7684\u5dee\u5f02\u6bd4\u8f83\u62a5\u544a\n  - `generate_markdown_diff_report`: Markdown\u683c\u5f0f\u7684\u5dee\u5f02\u62a5\u544a\u751f\u6210\n  - `generate_html_diff_report`: HTML\u683c\u5f0f\u7684\u5dee\u5f02\u62a5\u544a\u751f\u6210\n\n### \u5de5\u5177\u6a21\u5757\n- `graphql_to_httprunner/main.py`: \u7a0b\u5e8f\u5165\u53e3\u6a21\u5757\uff0c\u63d0\u4f9b\u547d\u4ee4\u884c\u754c\u9762\uff0c\u534f\u8c03\u8c03\u7528\u89e3\u6790\u5668\u548c\u751f\u6210\u5668\n- `graphql_to_httprunner/utils.py`: \u5de5\u5177\u7c7b\u6a21\u5757\uff0c\u63d0\u4f9b\u6587\u4ef6\u5907\u4efd\u548c\u5dee\u5f02\u6bd4\u8f83\u7b49\u901a\u7528\u529f\u80fd\n  - `backup_queries_file`: \u5907\u4efd\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\n  - `compare_query_files`: \u6bd4\u8f83\u65b0\u65e7\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\u7684\u5dee\u5f02\u5e76\u751f\u6210\u62a5\u544a\n- `graphql_to_httprunner/__main__.py`: \u5305\u6839\u76ee\u5f55\u5165\u53e3\u70b9\uff0c\u5141\u8bb8\u76f4\u63a5\u6a21\u5757\u8fd0\u884c\n- `graphql_to_httprunner/__init__.py`: \u5305\u521d\u59cb\u5316\u6587\u4ef6\uff0c\u63d0\u4f9b\u6a21\u5757\u5bfc\u5165\u63a5\u53e3\n- `__main__.py`: \u9879\u76ee\u6839\u76ee\u5f55\u5165\u53e3\u70b9\uff0c\u5141\u8bb8\u76f4\u63a5\u8fd0\u884c\u9879\u76ee\n\n### \u9879\u76ee\u7ed3\u6784\n```\ngraphql-schema-to-httprunner/\n\u251c\u2500\u2500 graphql_to_httprunner/        # \u4e3b\u5305\u76ee\u5f55\n\u2502   \u251c\u2500\u2500 __main__.py               # \u4e3b\u5305\u76ee\u5f55\u5165\u53e3\u70b9\n\u2502   \u251c\u2500\u2500 __init__.py               # \u5305\u521d\u59cb\u5316\u6587\u4ef6\n\u2502   \u251c\u2500\u2500 models.py                 # \u6570\u636e\u6a21\u578b\u6a21\u5757\n\u2502   \u251c\u2500\u2500 parser.py                 # \u89e3\u6790\u5668\u6a21\u5757\n\u2502   \u251c\u2500\u2500 introspection.py          # \u5185\u7701\u67e5\u8be2\u6a21\u5757\n\u2502   \u251c\u2500\u2500 generator.py              # \u751f\u6210\u5668\u6a21\u5757\n\u2502   \u251c\u2500\u2500 query_generator.py        # \u67e5\u8be2\u8bed\u53e5\u751f\u6210\u5668\u6a21\u5757\n\u2502   \u251c\u2500\u2500 report_generator.py       # \u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\u5dee\u5f02\u62a5\u544a\u751f\u6210\u5668\u6a21\u5757\n\u2502   \u251c\u2500\u2500 utils.py                  # \u5de5\u5177\u51fd\u6570\u6a21\u5757\n\u2502   \u2514\u2500\u2500 main.py                   # \u547d\u4ee4\u884c\u5165\u53e3\u6a21\u5757\n\u251c\u2500\u2500 tests/                        # \u5355\u5143\u6d4b\u8bd5\u76ee\u5f55\n\u251c\u2500\u2500 __main__.py                   # \u9879\u76ee\u6839\u76ee\u5f55\u5165\u53e3\u70b9\n\u251c\u2500\u2500 pyproject.toml                # \u9879\u76ee\u914d\u7f6e\u6587\u4ef6\n\u251c\u2500\u2500 setup.py                      # \u517c\u5bb9\u65e7\u5f0f\u5b89\u88c5\u7684\u914d\u7f6e\u6587\u4ef6\n\u251c\u2500\u2500 MANIFEST.in                   # \u6307\u5b9a\u6253\u5305\u65f6\u8981\u5305\u542b\u548c\u6392\u67e5\u7684\u6587\u4ef6\n\u2514\u2500\u2500 README.md                     # \u9879\u76ee\u8bf4\u660e\u6587\u6863\n```\n\n## \u4e09\u3001\u5b89\u88c5\u65b9\u6cd5\n\n### 3.1 \u4f7f\u7528pip\u5b89\u88c5\uff08\u63a8\u8350\uff09\n```bash\n# \u4ecePIPY\u4ed3\u5e93\u5b89\u88c5\npip install graphql-to-httprunner\n\n# \u6216\u8005\u4eceGit\u4ed3\u5e93\u5b89\u88c5\npip install git+https://git.umlife.net/zhangchuzhao/graphql-schema-to-httprunner.git\n```\n\n### 3.2 \u5f00\u53d1\u6a21\u5f0f\u5b89\u88c5\n```bash\n# \u4ece\u672c\u5730\u6e90\u7801\u5b89\u88c5\npip install .\n\n# \u4f7f\u7528pip\u5f00\u53d1\u6a21\u5f0f\u5b89\u88c5\npip install -e .\n\n# \u6216\u8005\u4f7f\u7528poetry\u5b89\u88c5\npoetry install\n```\n\n## \u56db\u3001\u4f7f\u7528\u65b9\u6cd5\n\n### 4.1 \u547d\u4ee4\u884c\u4f7f\u7528\uff08\u63a8\u8350\uff09\n\n\u5b89\u88c5\u540e\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528`gpl2hrun`\u6216`gpl2case`\u6216`graphql2httprunner`\u6216`graphql2testcase`\u547d\u4ee4\uff1a\n\n```bash\n# \u57fa\u4e8eschema.graphql\u6587\u4ef6\u751f\u6210HttpRunner\u7528\u4f8b\u5c42\u6d4b\u8bd5\u7528\u4f8b\ngpl2hrun -f schema.graphql -t -o testcases -u http://your-api-url -d 2\n\n# \u57fa\u4e8e\u5185\u7701\u67e5\u8be2URL\u751f\u6210HttpRunner\u7528\u4f8b\u5c42\u6d4b\u8bd5\u7528\u4f8b\ngpl2hrun -i http://your-graphql-server/graphql -t -o testcases -u http://your-api-url -d 2\n\n# \u57fa\u4e8eschema.graphql\u6587\u4ef6\u751f\u6210HttpRunner API\u5c42\u6d4b\u8bd5\u7528\u4f8b\ngpl2hrun -f schema.graphql -t --api -o api -u http://your-api-url -d 2\n\n# \u57fa\u4e8e\u5185\u7701\u67e5\u8be2URL\u751f\u6210HttpRunner API\u5c42\u6d4b\u8bd5\u7528\u4f8b\ngpl2hrun -i http://your-graphql-server/graphql -t --api -o api -u project_name -d 2\n\n# \u57fa\u4e8eschema.graphql\u6587\u4ef6\u751f\u6210HttpRunner\u7528\u4f8b\u5c42\u6d4b\u8bd5\u7528\u4f8b\uff08\u4ec5\u5305\u542b\u5fc5\u9009\u53c2\u6570\uff09\ngpl2hrun -f schema.graphql -t -o testcases --required\n\n# \u57fa\u4e8eschema.graphql\u6587\u4ef6\u751f\u6210HttpRunner API\u5c42\u6d4b\u8bd5\u7528\u4f8b\uff08\u4ec5\u5305\u542b\u5fc5\u9009\u53c2\u6570\uff09\ngpl2hrun -f schema.graphql -t --api -o api --required\n\n# \u57fa\u4e8eschema.graphql\u6587\u4ef6\u751f\u6210HttpRunner API\u5c42\u6d4b\u8bd5\u7528\u4f8b\uff08\u5305\u542b\u5173\u952e\u5b57\u53c2\u6570skip\uff09\ngpl2hrun -f schema.graphql -t --api -o api --skip\n\n# \u57fa\u4e8eschema.graphql\u6587\u4ef6\u751f\u6210HttpRunner API\u5c42\u6d4b\u8bd5\u7528\u4f8b\uff0c\u540c\u65f6\u751f\u6210\u5f15\u7528API\u7684\u6d4b\u8bd5\u7528\u4f8b\ngpl2hrun -f schema.graphql -t --api -o api --cite\n\n# \u57fa\u4e8eschema.graphql\u6587\u4ef6\u751f\u6210GraphQL\u67e5\u8be2\u8bed\u53e5\ngpl2hrun -f schema.graphql -q\n\n# \u57fa\u4e8eschema.graphql\u6587\u4ef6\u751f\u6210GraphQL\u67e5\u8be2\u8bed\u53e5\uff0c\u5e76\u9ed8\u8ba4\u4e0e\u65e7\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6query.yml\u8fdb\u884c\u5bf9\u6bd4\u751f\u6210\u5dee\u5f02\u62a5\u544a\uff08\u4e24\u79cd\u683c\u5f0f\uff09\ngpl2hrun -f schema.graphql -q --report both\n\n# \u57fa\u4e8eschema.graphql\u6587\u4ef6\u751f\u6210GraphQL\u67e5\u8be2\u8bed\u53e5\uff0c\u5e76\u751f\u6210Markdown\u683c\u5f0f\u5dee\u5f02\u62a5\u544a\ngpl2hrun -f schema.graphql -q --report markdown\n\n# \u57fa\u4e8eschema.graphql\u6587\u4ef6\u751f\u6210GraphQL\u67e5\u8be2\u8bed\u53e5\uff0c\u5e76\u751f\u6210HTML\u683c\u5f0f\u5dee\u5f02\u62a5\u544a\ngpl2hrun -f schema.graphql -q --report html\n\n# \u57fa\u4e8eschema.graphql\u6587\u4ef6\u751f\u6210GraphQL\u67e5\u8be2\u8bed\u53e5\uff0c\u5e76\u6307\u5b9a\u9879\u76ee\u540d\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\u5206\u7ec4\u6807\u8bc6\ngpl2hrun -f schema.graphql -q --project project_name\n\n# \u57fa\u4e8e\u5185\u7701\u67e5\u8be2URL\u751f\u6210GraphQL\u67e5\u8be2\u8bed\u53e5\ngpl2hrun -i http://your-graphql-server/graphql -q -o my.yml -u http://your-api-url -d 2\n\n# \u57fa\u4e8e\u5185\u7701\u67e5\u8be2URL\u751f\u6210GraphQL\u67e5\u8be2\u8bed\u53e5\uff0c\u5e76\u4e0e\u6307\u5b9a\u4e0emy.yml\u8fdb\u884c\u5bf9\u6bd4\u751f\u6210\u5dee\u5f02\u62a5\u544a\uff08\u4e24\u79cd\u683c\u5f0f\uff09\ngpl2hrun -i http://your-graphql-server/graphql -q -o my.yml -u http://your-api-url -d 2 --report both\n\n# \u57fa\u4e8e\u5185\u7701\u67e5\u8be2URL\u751f\u6210GraphQL\u67e5\u8be2\u8bed\u53e5\uff0c\u5e76\u751f\u6210HTML\u683c\u5f0f\u5dee\u5f02\u62a5\u544a\ngpl2hrun -i http://your-graphql-server/graphql -q -o my.yml -u http://your-api-url -d 2 --report html\n\n# \u4f7f\u7528\u914d\u7f6e\u6587\u4ef6\u6279\u91cf\u751f\u6210\u591a\u4e2a\u9879\u76ee\u7684HttpRunner\u6d4b\u8bd5\u7528\u4f8b\ngpl2hrun -b config.csv -t\n\n# \u4f7f\u7528\u914d\u7f6e\u6587\u4ef6\u6279\u91cf\u751f\u6210\u591a\u4e2a\u9879\u76ee\u7684GraphQL\u67e5\u8be2\u8bed\u53e5\u5217\u8868\uff0c\u751f\u6210\u8def\u5f84\u9ed8\u8ba4\u4e3aquery.yaml\ngpl2hrun -b config.csv -q\n\n# \u4f7f\u7528\u914d\u7f6e\u6587\u4ef6\u6279\u91cf\u751f\u6210\u591a\u4e2a\u9879\u76ee\u7684GraphQL\u67e5\u8be2\u8bed\u53e5\u5217\u8868\uff0c\u5e76\u9ed8\u8ba4\u4e0e\u65e7\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6query.yaml\u8fdb\u884c\u5bf9\u6bd4\u751f\u6210\u5dee\u5f02\u62a5\u544a\uff08\u4e24\u79cd\u683c\u5f0f\uff09\ngpl2hrun -b config.csv -q --report both\n\n# \u4f7f\u7528\u914d\u7f6e\u6587\u4ef6\u6279\u91cf\u751f\u6210\u591a\u4e2a\u9879\u76ee\u7684GraphQL\u67e5\u8be2\u8bed\u53e5\u5217\u8868\uff0c\u5e76\u751f\u6210Markdown\u683c\u5f0f\u5dee\u5f02\u62a5\u544a\ngpl2hrun -b config.csv -q --report markdown\n\n# \u4f7f\u7528\u914d\u7f6e\u6587\u4ef6\u6279\u91cf\u751f\u6210\u591a\u4e2a\u9879\u76ee\u7684GraphQL\u67e5\u8be2\u8bed\u53e5\u5217\u8868\uff0c\u751f\u6210\u8def\u5f84\u6307\u5b9a\u4e3amy_query.yaml\ngpl2hrun -b config.csv -q --queries-file my_query.yaml\n\n# \u4f7f\u7528\u914d\u7f6e\u6587\u4ef6\u6279\u91cf\u751f\u6210\u591a\u4e2a\u9879\u76ee\u7684GraphQL\u67e5\u8be2\u8bed\u53e5\u5217\u8868\uff0c\u5e76\u4e0e\u6307\u5b9amy_query.yaml\u8fdb\u884c\u5bf9\u6bd4\u751f\u6210\u5dee\u5f02\u62a5\u544a\uff08\u4e24\u79cd\u683c\u5f0f\uff09\ngpl2hrun -b config.csv -q --queries-file my_query.yaml --report both\n\n# \u4f7f\u7528\u914d\u7f6e\u6587\u4ef6\u6279\u91cf\u751f\u6210\u591a\u4e2a\u9879\u76ee\u7684GraphQL\u67e5\u8be2\u8bed\u53e5\u5217\u8868\uff0c\u5e76\u751f\u6210HTML\u683c\u5f0f\u5dee\u5f02\u62a5\u544a\ngpl2hrun -b config.csv -q --queries-file my_query.yaml --report html\n\n# \u6839\u636e\u914d\u7f6e\u6587\u4ef6\u548c\u67e5\u8be2\u8bed\u53e5\u5dee\u5f02\u62a5\u544a\u81ea\u52a8\u66f4\u65b0HttpRunner\u6d4b\u8bd5\u7528\u4f8b\uff0c\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\u9ed8\u8ba4\u4e3aquery.yaml\uff0c\u5e76\u751f\u6210\u9ed8\u8ba4HTML\u683c\u5f0f\u5dee\u5f02\u62a5\u544a\ngpl2hrun -b config.csv -a\n\n# \u6839\u636e\u914d\u7f6e\u6587\u4ef6\u548c\u67e5\u8be2\u8bed\u53e5\u5dee\u5f02\u62a5\u544a\u81ea\u52a8\u66f4\u65b0HttpRunner\u6d4b\u8bd5\u7528\u4f8b\uff0c\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\u9ed8\u8ba4\u4e3aquery.yaml\uff0c\u5e76\u751f\u6210Markdown\u683c\u5f0f\u5dee\u5f02\u62a5\u544a\ngpl2hrun -b config.csv -a --report markdown\n\n# \u6839\u636e\u914d\u7f6e\u6587\u4ef6\u548c\u67e5\u8be2\u8bed\u53e5\u5dee\u5f02\u62a5\u544a\u81ea\u52a8\u66f4\u65b0HttpRunner\u6d4b\u8bd5\u7528\u4f8b\uff0c\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\u6307\u5b9a\u4e3amy_query.yaml\ngpl2hrun -b config.csv -a --queries-file my_query.yaml\n\n# \u57fa\u4e8e\u5185\u7701\u67e5\u8be2URL\u751f\u6210\u64cd\u4f5c\u540d\u79f0 xxx \u7684HttpRunner\u7528\u4f8b\u5c42\u6d4b\u8bd5\u7528\u4f8b\ngpl2hrun -i http://localhost:8888/graphql -t --query-name xxx\n\n# \u57fa\u4e8e\u5185\u7701\u67e5\u8be2URL\u751f\u6210\u64cd\u4f5c\u540d\u79f0 xxx \u7684\u67e5\u8be2\u8bed\u53e5\npython . -i http://localhost:8888/graphql -q --project swapi --query-name xxx\n```\n\n\u914d\u7f6e\u6587\u4ef6\u683c\u5f0f\u4e3aCSV\uff0c\u5305\u542b\u4ee5\u4e0b\u5217\uff1a\n```\nproject_name,introspection_url,output,base_url,max_depth,required,api,is_cite,is_skip,offline\nswapi,http://localhost:8888/graphql,swapi,http://localhost:8888,2,false,false,false,false,false\nyoucloud,https://example-youcloud.com/graphql,youcloud,youcloud,5,true,true,false,true,false\nproject3,https://example-project2.com/graphql,project3,project3,6,true,true,true,true,true\n```\n\n- `project_name`: \u9879\u76ee\u540d\u79f0\uff0c\u7528\u4e8e\u6807\u8bc6\u548c\u65e5\u5fd7\u8f93\u51fa\n- `introspection_url`: GraphQL\u5185\u7701\u67e5\u8be2URL\n- `output`: \u8f93\u51fa\u76ee\u5f55\u8def\u5f84\uff0c\u6279\u91cf\u751f\u6210GraphQL\u67e5\u8be2\u8bed\u53e5\u65f6\u9ed8\u8ba4\u4e3aquery.yaml\n- `base_url`: GraphQL API\u57fa\u7840URL\n- `max_depth`: GraphQL\u67e5\u8be2\u5d4c\u5957\u7684\u6700\u5927\u6df1\u5ea6\n- `required`: \u662f\u5426\u53ea\u5305\u542b\u5fc5\u9009\u53c2\u6570\uff0c\u503c\u4e3a\"true\"\u6216\"false\"\n- `api`: \u662f\u5426\u751f\u6210API\u5c42\u6d4b\u8bd5\u7528\u4f8b\uff0c\u503c\u4e3a\"true\"\u6216\"false\"\n- `is_cite`: \u662f\u5426\u751f\u6210\u5f15\u7528API\u5c42\u7684\u6d4b\u8bd5\u7528\u4f8b\uff0c\u503c\u4e3a\"true\"\u6216\"false\"\n- `is_skip`: \u662f\u5426\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u662f\u5426\u5305\u542bskip\u5173\u952e\u8bcd\uff0c\u503c\u4e3a\"true\"\u6216\"false\"\n- `offline`: \u9879\u76ee\u662f\u5426\u5df2\u4e0b\u7ebf\uff0c\u503c\u4e3a\"true\"\u6216\"false\"\uff0c\u6279\u5904\u7406\u65f6\u4f1a\u8df3\u8fc7\u5df2\u4e0b\u7ebf\u9879\u76ee\n\n### 4.2 \u6e90\u7801\u6267\u884c\u4f7f\u7528\u65b9\u5f0f\n\n\u5982\u679c\u6ca1\u6709\u901a\u8fc7pip\u5b89\u88c5\uff0c\u6216\u8005\u9700\u8981\u76f4\u63a5\u8fd0\u884c\u6e90\u7801\uff0c\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u65b9\u5f0f\uff1a\n\n```bash\n# \u4f7f\u7528\u6839\u76ee\u5f55\u7684__main__.py\u5165\u53e3\u70b9\uff08\u7701\u7565\u6a21\u5757/\u6307\u5b9a\u6a21\u5757\uff09\npython . -f schema.graphql -t -o testcases -u http://your-api-url -d 2\npython __main__.py -f schema.graphql -t -o testcases -u http://your-api-url -d 2\n\n# \u4f7f\u7528\u5305\u76ee\u5f55__main__.py\u5165\u53e3\u70b9\npython -m graphql_to_httprunner -f schema.graphql -t -o testcases -u http://your-api-url -d 2\n\n# \u4f7f\u7528graphql_to_httprunner/main.py\u5165\u53e3\u70b9\npython -m graphql_to_httprunner.main -f schema.graphql -t -o testcases -u http://your-api-url -d 2\n```\n\n### 4.3 \u4ee3\u7801\u6a21\u5757\u4f7f\u7528\u65b9\u5f0f\n\n```python\nfrom graphql_to_httprunner.parser import GraphQLSchemaParser\nfrom graphql_to_httprunner.generator import HttpRunnerTestCaseGenerator\n\n# \u89e3\u6790GraphQL Schema\u6587\u4ef6\nwith open('schema.graphql', 'r') as f:\n    schema_content = f.read()\n    \nparser = GraphQLSchemaParser(schema_content)\nschema = parser.parse()\n\n# \u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\ngenerator = HttpRunnerTestCaseGenerator(schema, base_url=\"http://your-api-url\")\ntestcase_count = generator.generate_test_cases(\"testcases\")\nprint(f\"\u5df2\u751f\u6210{testcase_count}\u4e2a\u6d4b\u8bd5\u7528\u4f8b\")\n```\n\n### 4.4 \u53c2\u6570\u8bf4\u660e\n```bash\ngpl2hrun -h\n\nusage: gpl2hrun [-h] [-V] [-b BATCH] [-f SCHEMA_FILE | -i INTROSPECTION_URL] [-t | -q] [-o OUTPUT] [-u BASE_URL] [-d MAX_DEPTH] [--api] [--required] [-a] [--queries-file QUERIES_FILE]\n\n\u5c06GraphQL Schema\u8f6c\u6362\u4e3aHttpRunner\u6d4b\u8bd5\u7528\u4f8b\u6216\u67e5\u8be2\u8bed\u53e5\n\noptional arguments:\n  -h, --help\n  -V, --version\n  -b BATCH, --batch BATCH\n  -f SCHEMA_FILE, --schema-file SCHEMA_FILE\n  -i INTROSPECTION_URL, --introspection-url INTROSPECTION_URL\n  -t, --testcases\n  -q, --queries\n  -o OUTPUT, --output OUTPUT\n  -u BASE_URL, --base-url BASE_URL\n  -d MAX_DEPTH, --max-depth MAX_DEPTH\n  --api\n  --cite\n  --required\n  --skip\n  --report {markdown,html,both}\n  --project\n  -a, --auto-update\n  --queries-file QUERIES_FILE\n  --query-name QUERY_NAME\n```\n\n- `-b, --batch`: \u6279\u91cf\u5904\u7406\u914d\u7f6e\u6587\u4ef6\u8def\u5f84\uff0c\u5982 config.csv\n- `-f, --schema-file`: GraphQL Schema\u6587\u4ef6\u8def\u5f84\n- `-i, --introspection-url`: GraphQL\u5185\u7701\u67e5\u8be2URL\uff0c\u5982 http://localhost:9527/graphql\n- `-t, --testcases`: \u751f\u6210HttpRunner\u6d4b\u8bd5\u7528\u4f8b\n- `-q, --queries`: \u751f\u6210GraphQL\u67e5\u8be2\u8bed\u53e5\u5217\u8868\n- `--api`: \u751f\u6210API\u5c42\u6d4b\u8bd5\u7528\u4f8b\u800c\u975e\u7528\u4f8b\u5c42\u6d4b\u8bd5\u7528\u4f8b\uff08\u4ec5\u5f53\u4f7f\u7528 `-t` \u65f6\u6709\u6548\uff09\n- `--cite`: \u751f\u6210\u5f15\u7528API\u5c42\u6d4b\u8bd5\u7528\u4f8b\uff08\u4e0e--api\u9009\u9879\u4e00\u8d77\u4f7f\u7528\uff09\n- `--required`: \u53ea\u5305\u542b\u5fc5\u9009\u53c2\u6570\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u5305\u542b\u6240\u6709\u53c2\u6570\uff08\u4ec5\u5f53\u4f7f\u7528 `-t` \u65f6\u6709\u6548\uff09\n- `--skip`: \u751f\u6210\u7684\u6d4b\u8bd5\u7528\u4f8b\u662f\u5426\u5305\u542bskip\u5173\u952e\u8bcd\uff08\u4ec5\u5f53\u4f7f\u7528 `-t` \u65f6\u6709\u6548\uff09\n- `--report`: \u751f\u6210\u5dee\u5f02\u62a5\u544a\u683c\u5f0f\uff08\u4e0e-q\u9009\u9879\u4e00\u8d77\u4f7f\u7528\uff09\uff0c\u53ef\u9009\u503c\uff1a`markdown`\u3001`html`\u3001`both`\u3002\u5355\u9879\u76ee\u6a21\u5f0f\u9ed8\u8ba4\u4e0equery.yaml\u5bf9\u6bd4\u6216\u901a\u8fc7-o\u53c2\u6570\u6307\u5b9a\uff0c\u6279\u5904\u7406\u6a21\u5f0f\u9ed8\u8ba4\u4e0equery.yaml\u5bf9\u6bd4\u6216\u901a\u8fc7--queries-file\u53c2\u6570\u6307\u5b9a\n- `-o, --output`: \u751f\u6210\u7ed3\u679c\u8f93\u51fa\u8def\u5f84\uff0c\u6839\u636e\u751f\u6210\u7c7b\u578b\u9ed8\u8ba4\u4e3aapi\u3001testcases\u3001query.yml\u4e09\u79cd\u60c5\u51b5\uff08\u6ce8\u610f\uff1a\u6279\u6a21\u5f0f\u751f\u6210Graphql\u67e5\u8be2\u8bed\u53e5\u65f6\u9ed8\u8ba4\u4e3aquery.yaml\uff0c\u4ee5\u4fbf\u9002\u914d\u73b0\u6709\u811a\u672c\u5f15\u7528\u65b9\u5f0f\uff09\n- `-u, --base-url`: API\u57fa\u7840URL\u6216\u9879\u76ee\u540d\uff0c\u9879\u76ee\u540d\u7528\u6765\u4f5c\u4e3a\u81ea\u5b9a\u4e49\u51fd\u6570\u53c2\u6570\u751f\u6210API\u57fa\u7840URL\uff0c\u9ed8\u8ba4\u4e3a'http://localhost:8888'\n- `-d, --max-depth`: GraphQL\u67e5\u8be2\u5d4c\u5957\u7684\u6700\u5927\u6df1\u5ea6\uff0c\u9ed8\u8ba4\u4e3a2\n- `--project`: \u6307\u5b9a\u9879\u76ee\u540d\u79f0\uff0c\u4f5c\u4e3a\u751f\u6210\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\u5206\u7ec4\u6807\u8bc6\uff0c\u9ed8\u8ba4\u4e3aproject_name\n- `-a, --auto-update`: \u6839\u636eGraphQL\u67e5\u8be2\u8bed\u53e5\u5dee\u5f02\u62a5\u544a\u81ea\u52a8\u66f4\u65b0\u6d4b\u8bd5\u7528\u4f8b\uff08\u9700\u4e0e `-b` \u4e00\u8d77\u4f7f\u7528\uff09\n- `--queries-file`: \u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\u8f93\u51fa\u6216\u83b7\u53d6\u8def\u5f84\uff0c\u9ed8\u8ba4\u4e3aquery.yaml (\u4e0e-b\u9009\u9879\u4e00\u8d77\u4f7f\u7528)\n- `--query-name`: \u6307\u5b9a\u8981\u751f\u6210\u7684\u5355\u4e2a\u67e5\u8be2\u540d\u79f0\uff0c\u53ea\u751f\u6210\u8be5\u67e5\u8be2\u7684\u6d4b\u8bd5\u7528\u4f8b\u6216\u67e5\u8be2\u8bed\u53e5\n\n> \u6ce8\u610f\uff1a\n> - \u5f53\u6307\u5b9a `-b/--batch` \u53c2\u6570\u65f6\uff0c\u5de5\u5177\u5c06\u8fdb\u5165\u6279\u5904\u7406\u6a21\u5f0f\uff0c\u4ece\u914d\u7f6e\u6587\u4ef6\u4e2d\u8bfb\u53d6\u591a\u4e2a\u9879\u76ee\u4fe1\u606f\u8fdb\u884c\u6279\u91cf\u5904\u7406\n> - \u6279\u5904\u7406\u6a21\u5f0f\u4e0b\uff0c\u53ef\u4ee5\u540c\u65f6\u6307\u5b9a `-t/--testcases` \u6216 `-q/--queries` \u9009\u9879\u6765\u6307\u5b9a\u751f\u6210\u6d4b\u8bd5\u7528\u4f8b\u6216\u67e5\u8be2\u8bed\u53e5\n> - \u5355\u4e2a\u9879\u76ee\u6a21\u5f0f\u4e0b\uff08\u4e0d\u4f7f\u7528 `-b/--batch`\uff09\uff0c\u5fc5\u987b\u6307\u5b9a `-f/--schema-file` \u6216 `-i/--introspection-url` \u9009\u9879\uff0c\u4e14\u5fc5\u987b\u6307\u5b9a `-t/--testcases` \u6216 `-q/--queries` \u9009\u9879\n> - `-f` \u548c `-i` \u662f\u4e92\u65a5\u53c2\u6570\uff0c\u53ea\u80fd\u4e8c\u9009\u4e00\u4f7f\u7528\n> - `-t` \u548c `-q` \u662f\u4e92\u65a5\u53c2\u6570\uff0c\u53ea\u80fd\u4e8c\u9009\u4e00\u4f7f\u7528\n> - \u5982\u679c\u4f7f\u7528 `-t` \u9009\u9879\uff0c\u5219 `-o` \u53c2\u6570\u6307\u5b9a\u8f93\u51fa\u76ee\u5f55\uff1b\u5982\u679c\u4f7f\u7528 `-q` \u9009\u9879\uff0c\u5219 `-o` \u53c2\u6570\u6307\u5b9a\u8f93\u51fa\u6587\u4ef6\u8def\u5f84\n> - `--api` \u53c2\u6570\u4ec5\u5728 `-t` \u53c2\u6570\u5b58\u5728\u65f6\u6709\u6548\uff0c\u7528\u4e8e\u6307\u5b9a\u751f\u6210API\u5c42\u6d4b\u8bd5\u7528\u4f8b\n> - `--cite` \u53c2\u6570\u4ec5\u5728 `-t`\u548c`--api` \u53c2\u6570\u5b58\u5728\u65f6\u6709\u6548\uff0c\u7528\u4e8e\u6307\u5b9a\u751f\u6210\u5f15\u7528API\u5c42\u6d4b\u8bd5\u7528\u4f8b\n> - `--required` \u53c2\u6570\u4ec5\u5728 `-t` \u53c2\u6570\u5b58\u5728\u65f6\u6709\u6548\uff0c\u7528\u4e8e\u6307\u5b9a\u53ea\u5305\u542b\u5fc5\u9009\u53c2\u6570\n> - `--skip` \u53c2\u6570\u4ec5\u5728 `-t` \u53c2\u6570\u5b58\u5728\u65f6\u6709\u6548\uff0c\u7528\u4e8e\u6307\u5b9a\u751f\u6210\u7684\u6d4b\u8bd5\u7528\u4f8b\u662f\u5426\u5305\u542bskip\u5173\u952e\u8bcd\n> - `--report` \u53c2\u6570\u4ec5\u5728 `-q` \u6216 `-a` \u53c2\u6570\u5b58\u5728\u65f6\u6709\u6548\uff0c\u7528\u4e8e\u6307\u5b9a\u5dee\u5f02\u62a5\u544a\u683c\u5f0f\uff1a`markdown`\uff08\u53ea\u751f\u6210Markdown\u683c\u5f0f\uff09\u3001`html`\uff08\u53ea\u751f\u6210HTML\u683c\u5f0f\uff09\u3001`both`\uff08\u540c\u65f6\u751f\u6210\u4e24\u79cd\u683c\u5f0f\uff09\n\n### 4.5 \u6267\u884cHttpRunner\u6d4b\u8bd5\u7528\u4f8b\n```bash\n# \u8fd0\u884c\u7528\u4f8b\u5c42\u6d4b\u8bd5\u7528\u4f8b\nhrun testcases\n# \u8fd0\u884cAPI\u5c42\u6d4b\u8bd5\u7528\u4f8b\nhrun api\n```\n\n### 4.6 \u6253\u5305\u4e0a\u4f20PyPI\n```bash\n# \u6253\u6807\u7b7e\uff08\u8f7b\u91cf\u6216\u9644\u6ce8\uff09\ngit tag v1.0.0 \u6216 git tag -a v1.0.0 -m \"\u53d1\u5e03\u6b63\u5f0f\u7248\u672c v1.0.0\"\n# \u63a8\u9001\u6807\u7b7e(\u5355\u4e2a\u6216\u6240\u6709)\ngit push v1.0.0 \u6216 git push --tags\n# \u672c\u5730\u914d\u7f6epyproject.toml\u548cpypi token\u4fe1\u606f\npoetry config pypi-token xxx\n# \u7f16\u8bd1\u6253\u5305(\u66f4\u65b0__init__.py\u548cpyproject.toml\u4e2d\u7248\u672c\u53f7\uff0c poetry publish --build)\npoetry build\n# \u4e0a\u4f20\u53d1\u5e03\npoetry publish\n```\n\n\n## \u4e94\u3001\u6ce8\u610f\u4e8b\u9879\n1. \u6d4b\u8bd5\u7528\u4f8b\u4e2d\u4f7f\u7528$$\u6765\u8f6c\u4e49$\u7b26\u53f7\uff0c\u4ee5\u907f\u514d\u4e0eHttpRunner\u53d8\u91cf\u8bed\u6cd5\u51b2\u7a81\uff1b\n2. HttpRunner\u63a5\u53e3\u54cd\u5e94\u5185\u5bb9\u5f15\u7528\u53d8\u91cf\u7ea6\u5b9a\u4e3acontent\uff1b\n3. \u5185\u7701\u67e5\u8be2\u9700\u8981\u76ee\u6807GraphQL\u670d\u52a1\u652f\u6301\u6807\u51c6\u7684\u5185\u7701\u67e5\u8be2API\uff1b\n4. \u5185\u7701\u67e5\u8be2URL\u4e0e\u57fa\u7840URL\u4e0d\u540c\uff0c\u5206\u522b\u4f7f\u7528 `-i` \u548c `-u` \u53c2\u6570\u6307\u5b9a\uff1b\n5. \u751f\u6210\u7684\u67e5\u8be2\u8bed\u53e5\u5217\u8868\u4ee5YAML\u683c\u5f0f\u5b58\u50a8\uff0c\u952e\u4e3a\u64cd\u4f5c\u540d\u79f0\uff0c\u503c\u4e3a\u5bf9\u5e94\u7684\u67e5\u8be2\u8bed\u53e5\uff1b\n\n## \u516d\u3001\u67e5\u8be2\u8bed\u53e5\u5907\u4efd\u4e0e\u5dee\u5f02\u5bf9\u6bd4\u529f\u80fd\n\n### 6.1 \u81ea\u52a8\u5907\u4efd\u529f\u80fd\n\u5f53\u7528\u6237\u6267\u884c\u751f\u6210GraphQL\u67e5\u8be2\u8bed\u53e5\u5217\u8868\u4efb\u52a1\uff08\u4f7f\u7528`-q`\u53c2\u6570\uff09\u65f6\uff0c\u5de5\u5177\u4f1a\u81ea\u52a8\u68c0\u67e5\u662f\u5426\u5b58\u5728\u65e7\u7684\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\u3002\u5982\u679c\u5b58\u5728\uff0c\u5c06\u81ea\u52a8\u6267\u884c\u4ee5\u4e0b\u64cd\u4f5c\uff1a\n\n1. \u5c06\u65e7\u6587\u4ef6\u5907\u4efd\u4e3a\u5e26\u65f6\u95f4\u6233\u7684\u6587\u4ef6\uff0c\u683c\u5f0f\u4e3a`\u6587\u4ef6\u540d.bak.\u65f6\u95f4\u6233.\u6269\u5c55\u540d`\uff08\u4f8b\u5982\uff1a`query.yml.bak.20240501123456.yml`\uff09\n2. \u5220\u9664\u65e7\u7684\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\n3. \u751f\u6210\u65b0\u7684\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\n4. \u81ea\u52a8\u6267\u884c\u65b0\u65e7\u6587\u4ef6\u5dee\u5f02\u5bf9\u6bd4\n\n\u8fd9\u79cd\u81ea\u52a8\u5907\u4efd\u673a\u5236\u9002\u7528\u4e8e\u5355\u9879\u76ee\u6a21\u5f0f\u548c\u6279\u5904\u7406\u6a21\u5f0f\uff1a\n- \u5355\u9879\u76ee\u6a21\u5f0f\u4e0b\uff0c\u5907\u4efd\u6307\u5b9a\u7684\u8f93\u51fa\u6587\u4ef6\uff0c\u9ed8\u8ba4\u4e3a`query.yml`\n- \u6279\u5904\u7406\u6a21\u5f0f\u4e0b\uff0c\u5907\u4efd\u9ed8\u8ba4`query.yaml`\u6587\u4ef6\n\n### 6.2 \u5dee\u5f02\u5bf9\u6bd4\u62a5\u544a\n\u5dee\u5f02\u5bf9\u6bd4\u529f\u80fd\u4f1a\u81ea\u52a8\u5206\u6790\u65b0\u65e7\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\u7684\u5dee\u5f02\uff0c\u5e76\u6839\u636e\u6307\u5b9a\u7684\u683c\u5f0f\u751f\u6210\u8be6\u7ec6\u7684\u62a5\u544a\u3002\u652f\u6301\u4e09\u79cd\u62a5\u544a\u683c\u5f0f\uff1a\n\n- `markdown`\uff1a\u53ea\u751f\u6210Markdown\u683c\u5f0f\u62a5\u544a\n- `html`\uff1a\u53ea\u751f\u6210HTML\u683c\u5f0f\u62a5\u544a\n- `both`\uff1a\u540c\u65f6\u751f\u6210Markdown\u548cHTML\u683c\u5f0f\u62a5\u544a\uff08\u9ed8\u8ba4\u884c\u4e3a\uff09\n\n\u62a5\u544a\u5305\u542b\u4ee5\u4e0b\u4fe1\u606f\uff1a\n\n1. **\u9879\u76ee\u7ea7\u53d8\u66f4**\uff1a\u65b0\u589e\u9879\u76ee\u3001\u79fb\u9664\u9879\u76ee\n2. **\u67e5\u8be2\u7ea7\u53d8\u66f4**\uff1a\u9488\u5bf9\u6bcf\u4e2a\u4fee\u6539\u7684\u9879\u76ee\uff0c\u8be6\u7ec6\u5217\u51fa\u65b0\u589e\u67e5\u8be2\u3001\u79fb\u9664\u67e5\u8be2\u548c\u4fee\u6539\u67e5\u8be2\n3. **\u8be6\u7ec6\u5dee\u5f02**\uff1a\u5bf9\u4e8e\u4fee\u6539\u7684\u67e5\u8be2\uff0c\u63d0\u4f9b\u65e7\u503c\u3001\u65b0\u503c\u4ee5\u53ca\u8be6\u7ec6\u7684\u6587\u672c\u5dee\u5f02\u5bf9\u6bd4\n\n\u5dee\u5f02\u62a5\u544a\u6587\u4ef6\u683c\u5f0f\u4e3a`\u6587\u4ef6\u540d.\u65f6\u95f4\u6233.diff.md`\uff08\u4f8b\u5982\uff1a`query.yml.20240501123456.diff.md`\uff09\u548c`\u6587\u4ef6\u540d.\u65f6\u95f4\u6233.diff.html`\uff08\u4f8b\u5982\uff1a`query.yml.20240501123456.diff.html`\uff09\u3002\n\n### 6.3 \u5dee\u5f02\u5bf9\u6bd4\u793a\u4f8b\n\n\u4e0b\u9762\u662f\u4e00\u4e2aMarkdown\u683c\u5f0f\u5dee\u5f02\u62a5\u544a\u7684\u793a\u4f8b\u7247\u6bb5\uff1a\n\n````markdown\n# GraphQL API \u53d8\u66f4\u76d1\u6d4b\u62a5\u544a\n## \u65e7\u6587\u4ef6: query.yaml.bak.20240501123456.yaml\n## \u65b0\u6587\u4ef6: query.yaml\n\n## \u65b0\u589e\u9879\u76ee\n- project_new\n\n## \u4fee\u6539\u9879\u76ee\n### youcloud\n#### \u65b0\u589e\u67e5\u8be2\n- getNewFeature\n  ```\n  query getNewFeature {\n    newFeature {\n      id\n      name\n    }\n  }\n  ```\n\n#### \u4fee\u6539\u67e5\u8be2\n- getUserInfo\n  \u65e7:\n  ```\n  query getUserInfo {\n    user {\n      id\n      name\n    }\n  }\n  ```\n  \u65b0:\n  ```\n  query getUserInfo {\n    user {\n      id\n      name\n      email\n    }\n  }\n  ```\n  \u5dee\u5f02\u8be6\u60c5:\n  ```diff\n    query getUserInfo {\n      user {\n        id\n        name\n  +     email\n      }\n    }\n  ```\n````\n\n\u901a\u8fc7\u8fd9\u4e2a\u5dee\u5f02\u62a5\u544a\uff0c\u7528\u6237\u53ef\u4ee5\u6e05\u6670\u5730\u4e86\u89e3\u968f\u7740API\u5347\u7ea7\u548c\u8fed\u4ee3\uff0c\u67e5\u8be2\u8bed\u53e5\u53d1\u751f\u4e86\u54ea\u4e9b\u53d8\u5316\uff0c\u4fbf\u4e8e\u8fdb\u884cAPI\u53d8\u66f4\u7ba1\u7406\u548c\u6d4b\u8bd5\u7528\u4f8b\u7ef4\u62a4\u3002\n\n### 6.4 \u5de5\u5177\u7c7b\u6a21\u5757\n\n\u4e3a\u4e86\u589e\u5f3a\u4ee3\u7801\u7684\u53ef\u7ef4\u62a4\u6027\u548c\u6a21\u5757\u5316\uff0c\u9879\u76ee\u5c06\u6587\u4ef6\u5907\u4efd\u548c\u5dee\u5f02\u6bd4\u8f83\u529f\u80fd\u62bd\u79bb\u5230\u4e86\u5355\u72ec\u7684\u5de5\u5177\u7c7b\u6a21\u5757(`utils.py`)\uff0c\u4e3b\u8981\u63d0\u4f9b\u4ee5\u4e0b\u529f\u80fd\uff1a\n\n- `backup_queries_file`\uff1a\u8d1f\u8d23\u5c06\u73b0\u6709\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\u5907\u4efd\u4e3a\u5e26\u65f6\u95f4\u6233\u7684\u6587\u4ef6\uff0c\u5e76\u5220\u9664\u539f\u6587\u4ef6\n- `compare_query_files`\uff1a\u8d1f\u8d23\u6bd4\u8f83\u65b0\u65e7\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\u7684\u5dee\u5f02\uff0c\u5e76\u751f\u6210\u8be6\u7ec6\u7684Markdown\u683c\u5f0f\u5dee\u5f02\u62a5\u544a\n\n\u8fd9\u4e9b\u5de5\u5177\u51fd\u6570\u4f7f\u9879\u76ee\u66f4\u52a0\u6a21\u5757\u5316\uff0c\u4fbf\u4e8e\u7ef4\u62a4\u548c\u6269\u5c55\u3002\n\n## \u4e03\u3001\u6d4b\u8bd5\u7528\u4f8b\u81ea\u52a8\u66f4\u65b0\u529f\u80fd\n\n\u968f\u7740\u4ea7\u54c1\u8fed\u4ee3\u548cAPI\u53d8\u66f4\uff0cGraphQL\u67e5\u8be2\u8bed\u53e5\u4f1a\u4e0d\u65ad\u66f4\u65b0\uff0c\u5bfc\u81f4\u5df2\u751f\u6210\u7684HttpRunner\u6d4b\u8bd5\u7528\u4f8b\u9700\u8981\u624b\u52a8\u66f4\u65b0\u3002\u4e3a\u4e86\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\uff0c\u9879\u76ee\u5b9e\u73b0\u4e86\u6d4b\u8bd5\u7528\u4f8b\u81ea\u52a8\u66f4\u65b0\u529f\u80fd\uff0c\u80fd\u591f\u6839\u636e\u67e5\u8be2\u8bed\u53e5\u7684\u5dee\u5f02\u62a5\u544a\u81ea\u52a8\u66f4\u65b0\u76f8\u5e94\u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u3002\n\n### 7.1 \u81ea\u52a8\u66f4\u65b0\u6d41\u7a0b\n\n\u6d4b\u8bd5\u7528\u4f8b\u81ea\u52a8\u66f4\u65b0\u529f\u80fd\u7684\u5de5\u4f5c\u6d41\u7a0b\u5982\u4e0b\uff1a\n\n1. \u5907\u4efd\u73b0\u6709\u7684\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\n2. \u6839\u636e\u914d\u7f6e\u6587\u4ef6\u91cd\u65b0\u751f\u6210\u6700\u65b0\u7684\u67e5\u8be2\u8bed\u53e5\n3. \u6bd4\u8f83\u65b0\u65e7\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\uff0c\u751f\u6210\u5dee\u5f02\u62a5\u544a\n4. \u6839\u636e\u5dee\u5f02\u62a5\u544a\u81ea\u52a8\u5904\u7406\u4ee5\u4e0b\u53d8\u66f4:\n   - \u65b0\u589e\u9879\u76ee\uff1a\u81ea\u52a8\u751f\u6210\u65b0\u9879\u76ee\u7684\u6240\u6709\u6d4b\u8bd5\u7528\u4f8b\n   - \u79fb\u9664\u9879\u76ee\uff1a\u81ea\u52a8\u5220\u9664\u8be5\u9879\u76ee\u7684\u6d4b\u8bd5\u7528\u4f8b\u76ee\u5f55\n   - \u4fee\u6539\u9879\u76ee\uff1a\n     - \u65b0\u589e\u67e5\u8be2\uff1a\u81ea\u52a8\u751f\u6210\u65b0\u589e\u67e5\u8be2\u7684\u6d4b\u8bd5\u7528\u4f8b\n     - \u79fb\u9664\u67e5\u8be2\uff1a\u81ea\u52a8\u5220\u9664\u5bf9\u5e94\u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\n     - \u4fee\u6539\u67e5\u8be2\uff1a\u81ea\u52a8\u66f4\u65b0\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u7684\u67e5\u8be2\u8bed\u53e5\n\n### 7.2 \u4f7f\u7528\u65b9\u6cd5\n\n\u4f7f\u7528\u81ea\u52a8\u66f4\u65b0\u529f\u80fd\u9700\u8981\u63d0\u4f9b\u914d\u7f6e\u6587\u4ef6\u548c\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\uff1a\n\n```bash\n# \u4f7f\u7528\u9ed8\u8ba4\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6(query.yaml)\ngpl2hrun -b config.csv -a\n\n# \u6307\u5b9a\u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\ngpl2hrun -b config.csv -a --queries-file custom_queries.yaml\n```\n\n### 7.3 \u6ce8\u610f\u4e8b\u9879\n\n1. \u81ea\u52a8\u66f4\u65b0\u529f\u80fd**\u5fc5\u987b**\u4e0e\u6279\u5904\u7406\u6a21\u5f0f(`-b/--batch`)\u4e00\u8d77\u4f7f\u7528\n2. \u914d\u7f6e\u6587\u4ef6\u9700\u8981\u5305\u542b\u9879\u76ee\u540d\u79f0\u3001\u5185\u7701\u67e5\u8be2URL\u3001\u8f93\u51fa\u76ee\u5f55\u7b49\u4fe1\u606f\n3. \u67e5\u8be2\u8bed\u53e5\u6587\u4ef6\u5e94\u5f53\u5305\u542b\u6240\u6709\u9879\u76ee\u7684\u6700\u65b0\u67e5\u8be2\u8bed\u53e5\n4. \u81ea\u52a8\u66f4\u65b0\u8fc7\u7a0b\u4e2d\u5982\u679c\u9047\u5230\u9519\u8bef\uff0c\u4f1a\u5c3d\u53ef\u80fd\u7ee7\u7eed\u5904\u7406\u5176\u4ed6\u9879\u76ee\u548c\u67e5\u8be2\n5. \u81ea\u52a8\u66f4\u65b0\u5b8c\u6210\u540e\u4f1a\u8f93\u51fa\u7edf\u8ba1\u4fe1\u606f\uff0c\u5305\u62ec\u65b0\u589e\u9879\u76ee\u3001\u79fb\u9664\u9879\u76ee\u3001\u65b0\u589e\u67e5\u8be2\u3001\u79fb\u9664\u67e5\u8be2\u548c\u4fee\u6539\u67e5\u8be2\u7684\u6570\u91cf\n6. \u81ea\u52a8\u66f4\u65b0\u4f1a\u4fdd\u7559\u6d4b\u8bd5\u7528\u4f8b\u4e2d\u7684\u5176\u4ed6\u914d\u7f6e\u548c\u53c2\u6570\u503c\uff0c\u53ea\u66f4\u65b0\u67e5\u8be2\u8bed\u53e5\u90e8\u5206\uff0c\u4e0d\u5f71\u54cd\u5df2\u6709\u7684\u81ea\u5b9a\u4e49\u914d\u7f6e\n\n### 7.4 \u5de5\u5177\u51fd\u6570\n\n\u9879\u76ee\u6dfb\u52a0\u4e86\u4ee5\u4e0b\u5de5\u5177\u51fd\u6570\u4ee5\u652f\u6301\u6d4b\u8bd5\u7528\u4f8b\u81ea\u52a8\u66f4\u65b0\u529f\u80fd\uff1a\n\n- `find_testcase_files`\uff1a\u67e5\u627e\u4e0e\u6307\u5b9a\u67e5\u8be2\u5bf9\u5e94\u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\n- `delete_testcase_files`\uff1a\u5220\u9664\u4e0e\u6307\u5b9a\u67e5\u8be2\u5bf9\u5e94\u7684\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\n- `update_testcase_query`\uff1a\u66f4\u65b0\u6d4b\u8bd5\u7528\u4f8b\u6587\u4ef6\u4e2d\u7684\u67e5\u8be2\u8bed\u53e5\n- `determine_operation_type`\uff1a\u6839\u636e\u67e5\u8be2\u8bed\u53e5\u786e\u5b9a\u64cd\u4f5c\u7c7b\u578b\n- `auto_update_testcases`\uff1a\u6839\u636e\u5dee\u5f02\u62a5\u544a\u81ea\u52a8\u66f4\u65b0\u6d4b\u8bd5\u7528\u4f8b\n\n\u901a\u8fc7\u8fd9\u4e9b\u529f\u80fd\uff0c\u53ef\u4ee5\u5927\u5e45\u63d0\u9ad8API\u6d4b\u8bd5\u7528\u4f8b\u7684\u7ef4\u62a4\u6548\u7387\uff0c\u89e3\u51b3GraphQL API\u53d8\u66f4\u5bfc\u81f4\u7684\u6d4b\u8bd5\u7528\u4f8b\u5931\u6548\u95ee\u9898\u3002\n\n\n## \u516b\u3001\u5355\u5143\u6d4b\u8bd5\n\u9879\u76ee\u5305\u542b\u5b8c\u6574\u7684\u5355\u5143\u6d4b\u8bd5\u5957\u4ef6\uff0c\u8986\u76d6\u6240\u6709\u6838\u5fc3\u6a21\u5757\u529f\u80fd\u3002\n\n### 8.1 \u8fd0\u884c\u6d4b\u8bd5\n```bash\n# \u5b89\u88c5\u6d4b\u8bd5\u4f9d\u8d56\npoetry add -D pytest requests-mock pytest-cov\n\n# \u8fd0\u884c\u6240\u6709\u6d4b\u8bd5\npytest\n\n# \u8fd0\u884c\u7279\u5b9a\u6a21\u5757\u7684\u6d4b\u8bd5\npytest tests/test_models.py\n\n# \u8fd0\u884c\u6d4b\u8bd5\u5e76\u751f\u6210\u8986\u76d6\u7387\u62a5\u544a\npytest --cov=graphql_to_httprunner\n\n# \u751f\u6210HTML\u683c\u5f0f\u8986\u76d6\u7387\u62a5\u544a\npytest --cov=graphql_to_httprunner --cov-report=html\n```\n### 8.2 \u6d4b\u8bd5\u6587\u4ef6\u7ed3\u6784\n```\ntests/                          # \u6d4b\u8bd5\u76ee\u5f55\n\u251c\u2500\u2500 conftest.py                # \u6d4b\u8bd5\u914d\u7f6e\u6587\u4ef6\uff0c\u5b9a\u4e49\u6d4b\u8bd5\u5939\u5177\n\u251c\u2500\u2500 fixtures/                  # \u6d4b\u8bd5\u6570\u636e\u76ee\u5f55\n\u2502   \u2514\u2500\u2500 schema.graphql        # \u6d4b\u8bd5\u7528\u7684GraphQL Schema\n\u251c\u2500\u2500 test_models.py            # \u6570\u636e\u6a21\u578b\u6d4b\u8bd5\n\u251c\u2500\u2500 test_parser.py            # Schema\u89e3\u6790\u5668\u6d4b\u8bd5\n\u251c\u2500\u2500 test_introspection.py     # \u5185\u7701\u67e5\u8be2\u6d4b\u8bd5\n\u251c\u2500\u2500 test_generator.py         # \u6d4b\u8bd5\u7528\u4f8b\u751f\u6210\u5668\u6d4b\u8bd5\n\u251c\u2500\u2500 test_query_generator.py   # \u67e5\u8be2\u8bed\u53e5\u751f\u6210\u5668\u6d4b\u8bd5\n\u251c\u2500\u2500 test_report_generator.py  # \u5dee\u5f02\u62a5\u544a\u751f\u6210\u5668\u6d4b\u8bd5\n\u2514\u2500\u2500 test_utils.py             # \u5de5\u5177\u51fd\u6570\u6d4b\u8bd5\n```\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Automatically generate HttpRunner test cases based on GraphQL Schema",
    "version": "1.9.2",
    "project_urls": null,
    "split_keywords": [
        "graphql",
        " httprunner",
        " api",
        " automation",
        " test"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "9fb87ee13fc1075268a9019ef1f7240268a7407d5298188b4d949fd1c8c6f85d",
                "md5": "bc19dc807620ac9c1284636a30547c47",
                "sha256": "0c18e7d0df7e451ecd08a0d5ecfe9844fc23a5a6ff9adb7a59fba78abf000306"
            },
            "downloads": -1,
            "filename": "graphql_to_httprunner-1.9.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "bc19dc807620ac9c1284636a30547c47",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.5",
            "size": 43125,
            "upload_time": "2025-08-05T08:44:05",
            "upload_time_iso_8601": "2025-08-05T08:44:05.532033Z",
            "url": "https://files.pythonhosted.org/packages/9f/b8/7ee13fc1075268a9019ef1f7240268a7407d5298188b4d949fd1c8c6f85d/graphql_to_httprunner-1.9.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "5c56bdcd56e9e14a70a29e3a65f085b894eb718df6ed1e124077ae30b22a5888",
                "md5": "cbcbd38e3dc0a44f9ab10b5fa5e1e662",
                "sha256": "08f6abd8f890dfa6da9ed86dce7c1b2bc73029432e7659eb4656e258f8d94be8"
            },
            "downloads": -1,
            "filename": "graphql_to_httprunner-1.9.2.tar.gz",
            "has_sig": false,
            "md5_digest": "cbcbd38e3dc0a44f9ab10b5fa5e1e662",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.5",
            "size": 42453,
            "upload_time": "2025-08-05T08:44:07",
            "upload_time_iso_8601": "2025-08-05T08:44:07.661492Z",
            "url": "https://files.pythonhosted.org/packages/5c/56/bdcd56e9e14a70a29e3a65f085b894eb718df6ed1e124077ae30b22a5888/graphql_to_httprunner-1.9.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-05 08:44:07",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "graphql-to-httprunner"
}
        
Elapsed time: 1.91929s