###   1、编写项目配置文件

##### 1.1 项目配置文件总览

test_case文件夹下新建 projectSetting.json 项目配置文件

```text
{
	"environment": { 
		"default": "https://demo1.com",  # 默认接口请求域名
		"web": "https://demo2.com", 
		"app": "https://demo3.com"
	},
	"loginSetting": {
		"httpUser": {}, # http用户登录设置
		"webUser": {}, # web用户登录设置
		"appUser": {} # app用户登录设置
	},
	"platformHost": "http://123.25.112.113:8070" # 使用平台时平台域名地址
}
```

##### 1.2 项目用户登录配置

###### 1.2.1 httpUser 用户登录设置

① 支持miracle.py 中自定义函数登录

② 支持使用纯数据登录

```python
# miracle.py

import requests

def project_login(url, username, password):
    session = requests.session()
    response = session.post(url, json={"username": username, "password": password})
    try:
        token = response.json().get("detail").get("token")
        session.headers.update({"Authorization": f"Bearer {token}"})
        return session
    except Exception as e:
        raise e

```



```text
{	
    
    "user1": "${project_login(url='http://demo.com/api/auth/login/', username='username', password='password')}", # 使用miracle.py中自定义函数登录
    "user2": [ # 使用纯数据登录
        {
            "after": { # 发送接口请求后更新请求头信息（步骤节点最后执行）
                "header": {"Authorization": "Bearer @{token}"}
            }, 
            "bodyType": "json", # 接口请求数据类型
            "data": {"password": "123456", "username": "123456"}, # 接口请求数据
            "extract": ["token"], # 接口提取参数
            "method": "post", # 接口请求方法
            "url": "http://demo.com/api/auth/login/" # 接口请求路径
        },
        {"其他步骤": "当登录步骤需要多步完成时， 可继续按照步骤1编写"}
    ]
}
```



###### 1.2.2 webUser 用户登录设置

① 支持miracle.py 中自定义函数登录

② 支持使用纯数据登录

```text
{
    "user1": "${web_login(*args, **kwargs)}"  # 可自定义函数登录
    "user2": {
    	"caps": {"browser": "firefox"},
		"login_step": [ # 登录步骤
           {
               "eventName": "打开页面", "event": "open", 
               "url": "http://demo.com/login"
           },
           {
               "eventName": "输入用户名", "event": "input",
               "location": ["id", "username"], "input": "123456"
           },
           {
               "eventName": "输入密码", "event": "input",
               "location": ["id", "password"], "input": "123456"
           },
           {
               "eventName": "点击登录", "event": "click", 
               "location": ["id", "loginBtn"]
           }
        ]
	} 
}
```



###### 1.2.3 appUser 用户登录设置

① 支持miracle.py 中自定义函数登录

② 支持使用纯数据登录

```text
{
	"build_type": "yaml",
	"user1": {
		"hub": "",
		"caps": {  <设备连接参数>
            "platformName": "android",
            "deviceName": "xxx",
            "appPackage": "xxx",
            "appActivity": "xxx"
        },
        "login_step": [  <登录步骤>
			{
                "eventName": "输入用户名", "event": "input",
                "location": ["xpath", "XXX"], "input": "a02441"
            },
            {
                "eventName": "输入密码", "event": "input",
                "location": ["xpath", "XXX"], "input": "123456"
            },
            {
                "eventName": "点击登录", "event": "click", "location": ["xpath", "XXX"]
            }
        ]
	}
}
```



### 2、纯文本json结构编写测试用例

备注：编写测试用例文件均在脚手架test_case文件夹下进行

2.1 接口测试用例编写

test_api.json：编写测试用例json文件时需以 test 开头

```text
# test_api.json
[# 用例列表，每一个元素都是一条用例
    {
        "caseLevel": "P1",   # 用例等级
        "caseName": "购物车下单", # 用例名称
        "caseTier": "项目-首页-添加购物车-下单", # 用例目录
        "parametrize": [ # 参数化数据，每一行会参数化出一条测试用例
            {"_title": "参数化数据1", "username": "A02441", "password":  "Xu173798"},
            {"_title": "参数化数据2", "username": "A02441", "password":  "xu1"}
        ],
        "caseNodes": [ # 测试用例节点, 每一个元素为一个接口测试步骤
            {
                "step_name": "登录飞熊平台", # 测试步骤名
                "driver": "api", # 使用的驱动方式
                "user": "user2", # 使用的用户 api对应HttpUser的user2
                "param": { # requests.request对应的参数
                    "headers": {}, # 请求头
                    "method": "post", # 请求方法
                    "url": "http://123.25.112.113:8070/api/auth/login/", # 请求域名不填写默认使用projectSetting.json default域名 eg. /api/auth/login/= {default}/api/auth/login/
                    "json": {"username": "@{username}", "password":  "@{password}"} # @{xxxx}为参数替换，后续会详述
                },
                "assert_content": [{"eq":["status_code", 200]}], # 用例断言
                "extract": [["token", "token"]] # 用例参数提取
            }
        ]
    }
]
```

##### 2.2 web ui用例编写

test_web.json：编写测试用例json文件时需以 test 开头



```text
# test_web.json
[
    {
        "caseLevel": "P1",   # 用例等级
        "caseName": "购物车下单", # 用例名称
        "caseTier": "项目-首页-添加购物车-下单", # 用例目录
        "parametrize": [ # 参数化数据，每一行会参数化出一条测试用例
            {"_title": "参数化数据1", "username": "A02441", "password":  "123456"},
            {"_title": "参数化数据2", "username": "A02441", "password":  "123"}
        ],
        "caseNodes": [ # 测试用例节点, 每一个元素为一个接口测试步骤
            {   
                "step_name": "XXX"
                "user":  "user2", # 用户名 使用WebUser的user2
                "driver":"web", # 使用web驱动
                "param": {"eventName": "打开百度", "event": "open", "url": "https://www.baidu.com"}, # web-ui参数操作
                "assert_content": [] # 断言， 可写可不写
            },
            {   
                "step_name": "XXX"
                "user": "user2",
                "driver": "web",
                "param": {"eventName": "输入四季予你", "event": "input", "location": ["id", "kw"], "input": "四季予你"}
            },
            {
                "step_name": "XXX"
                "user": "user2",
                "driver": "web",
                "param": {"eventName": "点击百度一下", "event": "click", "location": ["id", "su"], "input": "四季予你"}
            }
        ]
    }
]
```
web_ui支持的event：
```text
{"eventName": "元素点击", "event": "click", "locations": ["css selector", "#kw"]}

eventName: 操作步骤名称

event：元素事件

location: ["元素定位方式", "元素定位表达式"]， 定位方式默认支持所有selenium定位方式

input：元素event为input时，输入内容

url：元素event为open时，浏览器打开url地址

target：元素event为move_to_element， move_to_point，移动到目标元素或者目标坐标点

attr： ["属性名称", "别名/新属性"](元素event为get_tag_attr, set_tag_attr)

```

```text
{"eventName": "元素点击", "event": "click", "locations": ["css selector", "#kw"]},

{"eventName": "输入内容", "event": "input", "locations": ["xpath", "#btn"], "input": "输入内容"},

{"eventName": "打开网页", "event": "open", "url": "输入内容"},

{"eventName": "键盘输入", "event": "key_event", "input": "回车/其他" },

{"eventName": "元素移动到元素位置", "event": "move_to_element", "location": ["id", "kw"], "target": ["id", "kw"]},

{"eventName": "元素移动某个坐标点", "event": "move_to_point", "location": ["id", "kw"], "target": [1, 2]},

{"eventName": "鼠标移动到指定元素位置", "event": "mouse_hover", "target": ["id", "kw"]},

{"eventName": "标签属性保存", "event": "get_tag_attr", "location": ["id", "kw"], "attr": ["attr_name（属性名）", "alias_name"（保存属性后别名）]},

{"eventName": "标签属性变更", "event": "set_tag_attr", "location": ["id", "kw"], "attr": ["attr_name（属性名）", "value（设置新的属性值）"]},
```
web_ui支持的断言：
```text
元素存在："assert_content": [{"ele_exits": ["id", "kw"]}]
元素不存在： "assert_content": [{"ele_not_exits": ["id", "kw"]}]
title存在："assert_content": [{"title_exits": "四季予你"}]
    部分匹配： "assert_content": [{"title_exits": "%予你"}]
              "assert_content": [{"title_exits": "四季%"}]
              "assert_content": [{"title_exits": "%季予%"}]
url存在： "assert_content": [{"url_exits": "四季予你"}]
公用断言： eq， not_eq··· ，接口支持的断言此处都支持。
    ① 提取页面标签TXT文本
        "assert_content": [{"eq": ["xpath://a[@id='su']/text()", "百度一下"]}]
        同时支持css，reg表达式，同接口html页面返回断言

```

##### 2.3 app ui用例编写

test_app.json：编写测试用例json文件时需以 test 开头

```text
# test_app.json
[
    {
        "caseLevel": "P2",
        "caseTier": "项目-首页-添加购物车-下单",
        "caseName": "购物车下单",
        "caseNodes": [
            {
                "stepName": "登录飞熊平台",
                "driver": "app",
                "user": "user1",
                "param":{"eventName": "点击登录", "event": "click", "locations": ["xpath", "//*[@text='登录']"], "input": "A02441"},
                "assert": [{"ele_exits":["id", "password"]}],
            }
        ]
    }
]
```
app_ui支持的event, 同web-ui元素事件
```text
{"eventName": "元素点击", "event": "click", "locations": ["css selector", "#kw"]},

{"eventName": "输入内容", "event": "input", "locations": ["xpath", "#btn"], "input": "输入内容"},

{"eventName": "打开网页", "event": "open", "url": "输入内容"},

{"eventName": "元素移动到元素位置", "event": "move_to_element", "location": ["id", "kw"], "target": ["id", "kw"]},

{"eventName": "元素移动某个坐标点", "event": "move_to_point", "location": ["id", "kw"], "target": [1, 2]},

{"eventName": "鼠标移动到指定元素位置", "event": "mouse_hover", "target": ["id", "kw"]},

{"eventName": "标签属性保存", "event": "get_tag_attr", "location": ["id", "kw"], "attr": ["attr_name", "alias_name"]},

{"eventName": "标签属性变更", "event": "set_tag_attr", "location": ["id", "kw"], "attr": ["attr_name", "value"]},
```
app-ui 支持的断言

```text
元素存在："assert_content": [{"ele_exits": ["id", "kw"]}]
元素不存在： "assert_content": [{"ele_not_exits": ["id", "kw"]}]
```

### 3、使用py文件编写测试用例

##### 3.1 py文件编写接口测试用例

① 脚手架 test_case 文件夹新建文件 test_api.py

```python
# test_api.py
from tools.step import Step
from miracle import get_data

class TestApi(Step):
    def test_api_01(self):
        pass
```

##### 3.2 py文件编写web UI测试用例

① 脚手架 test_case 文件夹新建文件 test_web.py

```python
# test_web.py
from tools.step import Step
from miracle import get_data

class TestAp(Step):
    def test_api_01(self):
        pass
```



##### 3.2 py文件编写app UI测试用例

① 脚手架 test_case 文件夹新建文件 test_app.py

```python
# test_app.py
from tools.step import Step
from miracle import get_data

class TestAp(Step):
    def test_api_01(self):
        pass
```



