swg2pyt 0.2.9
A helper generate swagger_client code to pytest format
Requires Python: >=3.4

# swg2pyt
### 代码准备
* 新建文件夹

* 安装模块 python -m pip install swg2pyt

* 生成swagger_client(路径分隔符有需要自行更正)
    ```
    java -jar .\swagger-codegen-cli.jar generate -i .\practice.json -l python -o .\practice_interface
    ```
    记住这个 practice_interface 文件夹

* 新建测试用例文件夹 practice_case

    并在 practice_case 下，创建如下结构的文件夹和xmind文件：
    ```
    xxx/xxx_data/xxx.xmind
    ```
    example：
    ```
    practice/practice_data/practice.xmind
    ```

* 假设现在xmind中已有有效用例
    ```
    from swg2pyt.ClassGenerator import ClassGenerator

    cg=ClassGenerator("practice_interface","practice_case")
    cg.generate()
    ```
    将生成如下：\
    practice_case/auto/\
    ├──test_xxx.py\
    ├──marks\
    同时会在xmind所在位置生成同名的 case.json ，建议只上传json至git

### xmind基本结构

函数名->请求类型和地址->TestCase->具体用例

其中：
- 函数名\
生成的swaggerapi中的真正函数名最短的那个，如practice_interface\\swagger_client\\api\
文件夹下practice_api.py中，定义有如下函数:
    ```
    def practice_using_post():
    和
    def practice_using_post_with_http_info():
    ```
    则函数名为 practice_using_post

- 请求类型和地址\
可于文档或代码中查找到：此处为\
    POST /return_as_is

- TestCase\
用例汇聚节点

### 用例结构
* 用例的最丰富组成结构为
    ```
        |-请求体
        |-其他入参
        |-描述
    用例名 |-预置条件
        |-断言
        |-mark
        |-order
    ```
* 请求体：最常见的情况是大部分接口请求参数（GET请求的query param，POST请求的body）被打包为param，且位于函数入参首位，这部分参数放入请求体

* 其他入参： 除请求体外直接出现在函数签名中的接口其他请求参数（可能用于header，url部分），这部分参数放入其他入参

* 预置条件：用于处理除自身外其他结构的数据，以及决定大部分测试框架行为

* 描述：功能无关的描述信息，生成test_xxx.py时，用作函数注释

* 断言：决定测试用例是否通过，以及重试次数

* mark用于标记用例，功能由pytest实现，只是可以写在这

* order用于改变用例执行顺序，但优先级低于预置条件中的precase和fromcase函数

### 用例基本执行流程
* 开始
* 由xmind 生成json（从这一步开始数据将从json中读取）
* 生成test_xxx.py(在测试用例文件夹下auto文件夹)
* pytest读取上一步生成的py，按mark collect用例
* 在pytest 完成collect用例后，按order重新排序用例
* （pytest执行用例期间）执行前置请求->预处理用例->发起请求->按设定次数重试
* pytest收尾
* 结束

### 预置条件主要作用
* 决定用例使用哪些fixture
* 改变请求体或其他入参，实现大部分动态数据功能，明面上或间接影响用例行为（主要是执行顺序），实现位于 Pretreator.py

### 断言主要作用
* 对用例返回的header，body和status做断言，实现位于 Asserter.py
* 当出现断言失败时，决定重试次数

### order主要作用
* 在用例中添加order并输入一个整数，可以变更用例执行顺序。默认的用例order为0（可以不写）。如果需要测试用例提前执行，填一个正数，如果需要测试用例延缓执行，则填一个负数，最终测试用例会按order从大到小的顺序执行，order相同的用例执行顺序暂不清楚，默认值的用例执行顺序可以参考它们在 test_xxx.py 中从上到下出现的顺序

### mark主要作用
* mark没有特别功能，pytest做什么，mark就做什么

### 框架主要作用
* 全自动读取测试用例，生成测试数据，执行
* 分离代码和测试数据
* 生成pytest可以识别的标准格式的test_*.py，使测试用例更易写易读易管理

### 预处理如何使用及常用函数介绍

* 预处理为一个字典，其中\
    顶级key为预处理范围，如请求体、其他入参、或断言\
    在顶级key的value（也是一个字典）中，次级key按xxx.yyy.zzz的格式选择将要处理的对象，次级value选择处理函数，例如
    ```
    请求体
    ——————————————
    {
        "xxx":{
            "yyy":{
                "zzz":"Hello world"
            }
        }
    }

    预置条件
    ——————————————
    {
        "请求体":{
            "xxx.yyy.zzz":{
                "replace":[
                    "world"，"pytest"
                ]
            }
        }
    }
    ```
* 预置条件将用replace函数处理请求体中的xxx.yyy.zzz的值\
* 其中replace预处理函数接受一个或两个入参（放在列表中）\
* 当仅有一个入参时，整个xxx.yyy.zzz会被这个入参完全替换\
* 当有两个入参时，则效果参考python标准库函数的replace\
* 这个预置条件顺利执行后，会将请求体的xxx.yyy.zzz的值替换为Hello pytest\
* 预处理函数的入参，即列表中的项还可以是其他预处理函数（字典），以实现更复杂的预处理\
* 常用预处理函数功能介绍（具体入参见代码）：

    - len 获取某个对象的长度，当对象为：
        - 字符串：获取字符串长度
        - 列表：获取列表个数
        - 字典：获取字典key的个数
    - toint：把字符串转换为整数
    - tofloat：把字符串转换为浮点数
    - tostr：把任何python支持的对象转换为str
    - range：返回一个标准range的列表
    - base64：返回一个字符串或文件内容的base64encode结果
    - tolist：将入参组合成一个列表并返回
    - todict：以入参奇数位为key，偶数位为value，返回一个字典
    - fixture：对于有返回值的fixture，从fixture处取值
    - replace：替换目标的全部或部分文本
    - precase：在执行当前用例之前，强行先执行列出的用例
    - fromcase：从目标用例处获取用例执行完成后的各来源值
    - timestamp：返回一个秒级（int）或毫秒级（float）时间戳
    - parametrize：使用了这个预处理函数的入参，入参列表有几个，该用例就会执行几次（与pytest无关），如果一个用例中有多个该预处理函数，则多个预处理函数并行，最终执行次数取决于入参列表最长的那个，不够长度的，取末尾值

### 断言如何使用
* 与预置条件类似，也是用keypath决定取值，但headers只需要一次key，status当前只返回status code\
    ```
    response
    ————————————————
    status_code:200
    headers:{"Connection:keep-alive"}
    body:
    {
        "xxx":{
            "yyy":{
                "zzz":"Success"
            }
        }
    }

    断言
    ————————————————
    {
        "headers":{
            "Connection":{
                "eq":"keep-alive"
                }
            }，
        "body":{
            "xxx.yyy.zzz":{
                "eq":"Success"`
            }
        }，
        "status":{"eq":200}，
        "retry":3
    }
    ```
* 可以使用的断言函数在 Asserter.py 中查看\
* 断言可以有多个，但整体用例断言结果为所有小断言的与值\
* 重试（retry）会在任意一个小断言失败时触发，效果为重新发起请求及再次尝试断言，断言失败继续重试，成功则通过用例。\
* 重试次数默认为1（不重试）

### 给框架加功能
* 实现简单的预处理和断言拓展，可以分别在 Pretreator.py 和 Asserer.py 中添加函数并“注册”到prtdict或astdict中，复杂的拓展可以配合修改 ClassGenerator.py ， Executor.py ， CaseCollector.py 实现
* 添加更多fixture，可以在 conftest.py 中添加函数并使用Pytest.fixture装饰器
* 想要改变pytest的行为，可以在 conftest.py 中添加“钩子函数”，或在预处理/断言代码中调用pytest函数