├── .gitignore
├── .idea
├── .gitignore
├── APItest.iml
├── encodings.xml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
└── modules.xml
├── 1.py
├── Common
├── 1.py
├── Base_test.py
├── Login.py
├── __init__.py
├── xmltest.py
└── yhapi.py
├── Config
└── conf.ini
├── Logs
└── log.py
├── README.md
├── data
├── a.xls
├── aBAK.xls
└── json
│ └── 1.py
├── getcwd.py
├── rdfile
├── __init__.py
├── rdExcel.py
└── rdini.py
├── report
└── allure_result
│ ├── 32425007-3e44-4707-824b-5eb16ca4f7b7-result.json
│ ├── c6868cd2-d85d-4095-9c18-c0e73e7c531d-container.json
│ └── dea0c60d-318d-4f99-a7b0-1d892cb8ca32-attachment.txt
└── test_pytest
├── __init__.py
├── test_api.py
└── test_two.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | ENV/
110 | env.bak/
111 | venv.bak/
112 |
113 | # Spyder project settings
114 | .spyderproject
115 | .spyproject
116 |
117 | # Rope project settings
118 | .ropeproject
119 |
120 | # mkdocs documentation
121 | /site
122 |
123 | # mypy
124 | .mypy_cache/
125 | .dmypy.json
126 | dmypy.json
127 |
128 | # Pyre type checker
129 | .pyre/
130 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Datasource local storage ignored files
5 | /dataSources/
6 | /dataSources.local.xml
7 | # Editor-based HTTP Client requests
8 | /httpRequests/
9 |
--------------------------------------------------------------------------------
/.idea/APItest.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/1.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # @Time : 2021-4-22 11:31
3 | # @Author : 奥斯卡
4 | # @Email : 1203069758@qq.com
5 | # @File : 1.py
6 |
7 | from Logs.log import log1
8 | try:
9 | log1.info("开始测试")
10 | r = 10/0
11 | log1.info("resuit:", r)
12 | except ZeroDivisionError as e:
13 | log1.error("报错信息:", exc_info=1)
14 | log1.info('end')
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Common/1.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | os.path.dirname(__file__) # 获取当前目录
4 | os.path.dirname(os.path.dirname(__file__)) # 获取当前目录的上一级
5 |
6 |
7 | # 获取指定的目录
8 | def fileDir(data):
9 | """
10 | :param data: 目录
11 | :return: 返回
12 | """
13 | base_path = os.path.dirname(os.path.dirname(__file__))
14 | return os.path.join(base_path, data) # 将获取到的目录返回
15 |
16 |
17 | # 获取路径下的文件,调用需要传递两个参数替换,否则使用默认的参数
18 | def filePath(fileDir="data", fileName="data.xls"):
19 | """
20 | :param fileDir:目录
21 | :param fileName: 文件名称
22 | :return: 返回
23 | """
24 | return os.path.join(os.path.dirname(os.path.dirname(__file__)), fileDir, fileName)
25 |
26 | print(fileDir('test_api.py'))
27 |
--------------------------------------------------------------------------------
/Common/Base_test.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from Logs.log import log1
3 | import json
4 |
5 | class ApiRequest(object):
6 | # -----第一种请求方式封装request库,调用可根据实际情况传参
7 | def send_requests(self, method, url, data=None, params=None, headers=None, cookies=None, json=None, files=None,
8 | timeout=None):
9 | self.res = requests.request(method, url, data=data, params=params, headers=headers, cookies=cookies, json=json,
10 | files=files, timeout=timeout)
11 | return self.res
12 |
13 |
14 | def getdict(self, dict1, obj, default=None):
15 | ''' 遍历嵌套字典,得到想要的value
16 | dict1所需遍历的字典
17 | obj 所需value的键'''
18 | for k, v in dict1.items():
19 | if k == obj:
20 | return v
21 | else:
22 | if type(v) is dict: # 如果是字典
23 | re = self.getdict(v, obj, default) # 递归
24 | if re is not default:
25 | return re
26 |
27 | def get_header(self, headers):
28 | '''
29 | 将从浏览器复制过来的headers转换成字典
30 | '''
31 | headers = dict([line.split(": ", 1) for line in headers.split("\n")])
32 | return headers
33 |
34 | # c='''Connection: keep-alive
35 | # Content-Length: 110
36 | # Pragma: no-cache
37 | # Cache-Control: no-cache
38 | # Accept: application/json, text/plain, */*
39 | # User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36
40 | # Content-Type: application/json;charset=UTF-8
41 | # Origin: http://172.25.16.6:8090
42 | # Referer: http://172.25.16.6:8090/
43 | # Accept-Encoding: gzip, deflate
44 | # Accept-Language: zh-CN,zh;q=0.9'''
45 | # headers = dict([line.split(": ", 1) for line in c.split("\n")])
46 | # print(headers)
47 |
--------------------------------------------------------------------------------
/Common/Login.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # @Time : 2021-5-7 19:25
3 | # @Author : 奥斯卡
4 | # @Email : 1203069758@qq.com
5 | # @File : Login.py
6 | import requests
7 | import re
8 |
9 |
10 | class cookie():
11 | def __init__(self):
12 | '''这里登录用的账号密码是zzzfwld/12345678Aa'''
13 | self.url = "http://localhost:999/bi/api?action=login"
14 | self.headers = {'content-type': 'application/x-www-form-urlencoded'}
15 | self.data = {'adminv': 'admin', 'passv': 'g5'}
16 | self.request = requests.session()
17 |
18 | def login(self):
19 | '''
20 | :return: 这一步是登录,返回登录成功的cookies.后面的操作拿到cookies,就能直接操作接口了
21 | '''
22 | # 先获取拼接到的的data和cookies。因为创建session的时候需要cookie
23 | # 使用旧cookie登录,然后得到登录后的新cookie
24 | # 使用新cookie就可以操作接口
25 | res = self.request.post(self.url, headers=self.headers, data=self.data)
26 | token = re.search('(.*?)', res.text, re.M | re.I)
27 | # print("token值等于", token.group(1))
28 | token = token.group(1)
29 | return token
30 |
31 |
32 | # r = cookie().login()
33 |
--------------------------------------------------------------------------------
/Common/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oscear/autoTest-for-api/f6de611c1c69ffc35dcdda7ffb2936b3a818ef69/Common/__init__.py
--------------------------------------------------------------------------------
/Common/xmltest.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from xml.etree import ElementTree
3 | qq_str = '1203069758'
4 | url_str ='http://www.webxml.com.cn//webservices//qqOnlineWebService.asmx//qqCheckOnline?qqCode=%s'%qq_str
5 | text_str = requests.get(url_str)
6 | text_str.encoding='utf-8'
7 | #解析xml格式内容,将字符串转为特殊的对象
8 |
9 |
10 | node = ElementTree.XML(text_str.text)
11 | print("node等于",node.text)
12 |
13 | tree = ElementTree.fromstring(text_str.content)
14 | print("node2等于",tree.text)
--------------------------------------------------------------------------------
/Common/yhapi.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : OSCar
4 | # @Time : 2021/11/5 16:46
5 | # @File : yhapi.py
6 | # @Project : myblog
7 | # @Mail : 1203069758@qq.com
8 | import requests
9 | from xml.etree import ElementTree as ET
10 | import json
11 | import xmltodict
12 |
13 | url = "http://127.0.0.1:999/bi/api?action=shareDB&token="
14 | token = "80D4B9499F3FB36E20F5ECD45E2D8FD3"
15 | url2 = url + token
16 | data = {'xmlData': '''
17 |
18 |
19 | [
20 | sharedb
21 | db
22 | ]
23 |
24 |
25 | [
26 | user
27 | a
28 | ]
29 |
30 |
31 | '''
32 | }
33 | headers = {'content-type': 'application/xml'}
34 |
35 | res = requests.post(url2, headers=headers, data=data)
36 | print('res的结果是', res.text)
37 |
38 | # resDict = json.loads(res.content,strict=False)
39 |
40 | resDict2 = xmltodict.parse(res.text)
41 | # print('resdict等于', resDict)
42 | print('resdict等于', resDict2)
43 | print('resdict类型', type(resDict2))
44 | print('resdict类型', resDict2['results']['result']['level'])
45 | print('resdict类型', resDict2['results']['result']['message'])
46 |
--------------------------------------------------------------------------------
/Config/conf.ini:
--------------------------------------------------------------------------------
1 | [url]
2 | ip=127.0.0.1
3 | port=999
4 |
5 | [database]
6 | aa=1
7 |
8 | [sql]
9 | bb=2
10 |
11 |
--------------------------------------------------------------------------------
/Logs/log.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # @Time : 2021-4-22 11:30
3 | # @Author : 奥斯卡
4 | # @Email : 1203069758@qq.com
5 | # @File : log.py
6 | import logging
7 | import time
8 | import os
9 | import getcwd
10 |
11 |
12 | def get_log(logger_name):
13 | # 创建一个logger
14 | logger = logging.getLogger(logger_name)
15 | logger.setLevel(logging.INFO)
16 |
17 | # 设置日志存放路径,日志文件名
18 | # 获取本地时间,转换为设置的格式
19 | rq = time.strftime('%Y%m%d%H%M', time.localtime(time.time()))
20 | # 设置所有日志和错误日志的存放路径
21 | path = getcwd.get_cwd()
22 | # 通过getcwd.py文件的绝对路径来拼接日志存放路径
23 | all_log_path = os.path.join(path, 'Logs/All_Logs/')
24 | error_log_path = os.path.join(path, 'Logs/ERROR_Logs/')
25 | # 设置日志文件名
26 | all_log_name = all_log_path + rq + '.log'
27 | error_log_name = error_log_path + rq + '.log'
28 |
29 | # 创建handler
30 | # 创建一个handler写入所有日志
31 | fh = logging.FileHandler(all_log_name)
32 | fh.setLevel(logging.INFO)
33 | # 创建一个handler写入错误日志
34 | eh = logging.FileHandler(error_log_name)
35 | eh.setLevel(logging.ERROR)
36 | # 创建一个handler输出到控制台
37 | ch = logging.StreamHandler()
38 | ch.setLevel(logging.INFO)
39 |
40 | # 定义日志输出格式
41 | # 以时间-日志器名称-日志级别-日志内容的形式展示
42 | all_log_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
43 | # 以时间-日志器名称-日志级别-文件名-函数行号-错误内容
44 | error_log_formatter = logging.Formatter(
45 | '%(asctime)s - %(name)s - %(levelname)s - %(module)s - %(lineno)s - %(message)s')
46 | # 将定义好的输出形式添加到handler
47 | fh.setFormatter(all_log_formatter)
48 | ch.setFormatter(all_log_formatter)
49 | eh.setFormatter(error_log_formatter)
50 |
51 | # 给logger添加handler
52 | logger.addHandler(fh)
53 | logger.addHandler(eh)
54 | logger.addHandler(ch)
55 | return logger
56 |
57 |
58 | log1 = get_log("YongHongApi")
59 |
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Python+Requests+PyTest+Excel+Allure接口自动化测试实战
2 |
3 | #### 目录说明
4 | - **common**
5 | 公用的基础方法,连接数据库执行SQL语句、获取多层嵌套dict中某一个key的值等
6 | - **config**
7 | 存放配置文件
8 | - **Data**
9 | 存放测试用户和测试相关数据
10 | - **Logs**
11 | 存放日志
12 | - **test_pytest**
13 | 测试用例执行目录,里面只写具体的测试用例代码,测试用例要以test_开头或者以_test结尾,测试用例不改变的情况下,这里面的代码编写好后一般不需要进行修改
14 | - **rdFile**
15 | 读取各类文件,目前只包含有excel、ini,后续扩充
16 | - **conftest.py**
17 | 与conftest.py同目录的文件执行时都会执行该文件
18 | 目前创建driver对象和运行失败截图的放在此文件中的
19 | * **Report**
20 | 保存运行结果的目录,用的是allure来生成的报告,多个json文件:
21 | 也可通过jenkins集成allure报告,可看到执行结果的趋势
22 |
--------------------------------------------------------------------------------
/data/a.xls:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oscear/autoTest-for-api/f6de611c1c69ffc35dcdda7ffb2936b3a818ef69/data/a.xls
--------------------------------------------------------------------------------
/data/aBAK.xls:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oscear/autoTest-for-api/f6de611c1c69ffc35dcdda7ffb2936b3a818ef69/data/aBAK.xls
--------------------------------------------------------------------------------
/data/json/1.py:
--------------------------------------------------------------------------------
1 | a='''王老吉'''
2 | res='''{'customData': {}, 'data': [{'jbld': '王老吉', 'fkdwNum': 1, 'bh': '000154b80c8646f4913ebd11286c3fad', 'jbrq': '2021-09-25', 'zjsdwNum': 1, 'cjsj': '2021-04'''
3 | if a in res:
4 | print('通过')
--------------------------------------------------------------------------------
/getcwd.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # @Time : 2021-4-22 11:27
3 | # @Author : 奥斯卡
4 | # @Email : 1203069758@qq.com
5 | # @File : getcwd.py
6 | import os
7 | def get_cwd():
8 | path = os.path.dirname(os.path.abspath(__file__))
9 | #当前文件的绝对路径
10 | return path
11 |
12 | os.getcwd()#获取当前目录
13 | os.path.dirname(__file__)#获取当前目录
14 | os.path.dirname(os.path.dirname(__file__))#获取当前目录的上一级
--------------------------------------------------------------------------------
/rdfile/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # @Time : 2021-4-27 19:45
3 | # @Author : 奥斯卡
4 | # @Email : 1203069758@qq.com
5 | # @File : __init__.py
6 |
--------------------------------------------------------------------------------
/rdfile/rdExcel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : OSCar
4 | # @Time : 2021/11/5 18:53
5 | # @File : rdExcel.py
6 | # @Project : myblog
7 | # @Mail : 1203069758@qq.com
8 |
9 | import xlrd
10 | import getcwd
11 | import os
12 |
13 | path = getcwd.get_cwd()
14 |
15 | class read_excel():
16 |
17 | def __init__(self, xls, sheet):
18 | '''
19 | @param xls: 传入excel的名字
20 | @param sheet: 传入sheet的名字,注意大小写
21 | '''
22 | self.excelpath = os.path.join(path, 'data/' + xls)
23 | # 打开excel
24 | self.book = xlrd.open_workbook(self.excelpath)
25 | # 获取excel
26 | self.sheet = self.book.sheet_by_name(sheet)
27 |
28 | # 以列表形式读取出所有数据
29 | def getExceldatas(self):
30 | data = []
31 | title = self.sheet.row_values(0)
32 | # 0获取第一行也就是表头
33 | print("用例总条数为", self.sheet.nrows)
34 | for row in range(0, self.sheet.nrows): # 从第一行包括表头开始获取
35 | row_value = self.sheet.row_values(row)
36 | data.append(dict(zip(title, row_value))) # 将读取出每一条用例作为一个字典存放进列表
37 | return data
38 |
39 |
40 | def get_nrows(self):
41 | '''获取列表行数'''
42 | return self.sheet.nrows
43 |
44 |
45 |
46 | # hc = OperationExcel('a.xls','Sheet1')
47 | # print(hc.getExceldatas())
48 | # print(type(hc.getExceldatas()))
49 | # print()
50 | #
51 | # for i in range(1, hc.get_nrows()):
52 | # num = i - 1
53 | # print('num的顺序为', num)
54 | # host = hc.getExceldatas()[num]['Host']
55 | # print(host)
--------------------------------------------------------------------------------
/rdfile/rdini.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # @Time : 2021-4-2 17:02
3 | # @Author : 奥斯卡
4 | # @Email : 1203069758@qq.com
5 | # @File : Readini.py
6 | import configparser
7 | import os
8 | import getcwd
9 |
10 |
11 | path = getcwd.get_cwd()
12 |
13 |
14 | def read_ini(section, name):
15 | rf = configparser.ConfigParser()
16 | inipath = os.path.join(path, 'Config/conf.ini')
17 | # rf.read("..\Config\conf.ini")
18 | rf.read(inipath)
19 | key = rf.get(section, name)
20 | return key
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/report/allure_result/32425007-3e44-4707-824b-5eb16ca4f7b7-result.json:
--------------------------------------------------------------------------------
1 | {"name": "test_api", "status": "passed", "attachments": [{"name": "log", "source": "dea0c60d-318d-4f99-a7b0-1d892cb8ca32-attachment.txt", "type": "text/plain"}], "start": 1636725331773, "stop": 1636725331895, "uuid": "3d5d4a55-297b-4d35-9377-49aec3c7a971", "historyId": "cd7303856ea89c1d705a4a4324eb4172", "testCaseId": "b04a447cc074f51f2c2bf27f3180eb4c", "fullName": "test_pytest.test_two.TestYongHong#test_api", "labels": [{"name": "parentSuite", "value": "test_pytest"}, {"name": "suite", "value": "test_two"}, {"name": "subSuite", "value": "TestYongHong"}, {"name": "host", "value": "LAPTOP-SL67I6GL"}, {"name": "thread", "value": "12608-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "test_pytest.test_two"}]}
--------------------------------------------------------------------------------
/report/allure_result/c6868cd2-d85d-4095-9c18-c0e73e7c531d-container.json:
--------------------------------------------------------------------------------
1 | {"uuid": "47a2513a-513b-48f5-a301-51f192b44dff", "children": ["3d5d4a55-297b-4d35-9377-49aec3c7a971"], "befores": [{"name": "xunit_setup_class_fixture_TestYongHong", "status": "passed", "start": 1636725331767, "stop": 1636725331768}], "afters": [{"name": "xunit_setup_class_fixture_TestYongHong::0", "status": "passed", "start": 1636725331895, "stop": 1636725331896}], "start": 1636725331767, "stop": 1636725331896}
--------------------------------------------------------------------------------
/report/allure_result/dea0c60d-318d-4f99-a7b0-1d892cb8ca32-attachment.txt:
--------------------------------------------------------------------------------
1 | INFO YongHongApi:test_two.py:51 正在测试的接口编号是:1.0,名称是分享报告
2 | ERROR YongHongApi:test_two.py:53 当前接口运行有误,其编号是2.0
3 | INFO YongHongApi:test_two.py:51 正在测试的接口编号是:3.0,名称是替换数据集
4 | INFO YongHongApi:test_two.py:51 正在测试的接口编号是:4.0,名称是新增用户
5 | INFO YongHongApi:test_two.py:51 正在测试的接口编号是:5.0,名称是删除用户
6 | INFO YongHongApi:test_two.py:51 正在测试的接口编号是:6.0,名称是新增admin
7 | INFO YongHongApi:test_two.py:51 正在测试的接口编号是:7.0,名称是删除admin
--------------------------------------------------------------------------------
/test_pytest/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : OSCar
4 | # @Time : 2021/11/5 17:49
5 | # @File : __init__.py.py
6 | # @Project : myblog
7 | # @Mail : 1203069758@qq.com
8 |
--------------------------------------------------------------------------------
/test_pytest/test_api.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : OSCar
4 | # @Time : 2021/11/5 17:49
5 | # @File : test_api.py
6 | # @Project : apitest
7 | # @Mail : 1203069758@qq.com
8 | import os
9 | import pytest
10 | from rdfile.rdini import read_ini
11 | from rdfile.rdExcel import read_excel
12 | from Common.Base_test import ApiRequest
13 | from Common.Login import cookie
14 | from Logs.log import log1
15 |
16 |
17 | class TestYongHong:
18 |
19 |
20 | def setup_class(self):
21 | print('开始测试')
22 |
23 |
24 | def teardown_class(self):
25 | print('结束测试')
26 |
27 | def test_api(self):
28 | token = cookie().login()
29 | ip = read_ini('url', 'ip')
30 | port = read_ini('url', 'port')
31 | datatable = read_excel('a.xls', 'Sheet1')
32 | data = datatable.getExceldatas()
33 | # 读出来是个列表内包含字典
34 |
35 | try:
36 | # 因为第一行是excel表头,从第二行开始获取
37 | for i in range(1, datatable.get_nrows()):
38 | path = data[i]['path']
39 | method = data[i]['method']
40 | headers = data[i]['headers']
41 | body = data[i]['data']
42 | # 前面是从excel取得值
43 | url = 'http://' + ip + ':' + port + path + token
44 | # print('url是', url)
45 | # 拼接url
46 | checkpoint = data[i]['check']
47 | res = ApiRequest().send_requests(method=method, url=url, headers=eval(headers), data=eval(body))
48 | # print('res等于', res.text)
49 | log1.info("正在测试的接口编号是:%s,名称是%s" % (data[i]['c_bh'], data[i]['name']))
50 | assert checkpoint in res.text, '响应内容错误'
51 | except Exception:
52 | log1.error("有接口预期不符")
53 |
54 |
55 | if __name__ == '__main__':
56 | # os.system(r'del /f /q ..\Logs\ALL_Logs')
57 | # os.system(r'del /f /q ..\Logs\ERROR_Logs') # 先删除旧日志
58 | pytest.main(['-s', '-v', 'test_api.py', '--clean-alluredir', '--alluredir', '../report/allure_result'])
59 | os.system(r'allure serve ../report/allure_result')
60 | # 等同于在dos执行:pytest -s -v --clean-alluredir --alluredir ../report/allure_result
61 | # 等同于在dos执行: allure serve ../report/allure_result
62 |
--------------------------------------------------------------------------------
/test_pytest/test_two.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : OSCar
4 | # @Time : 2021/11/5 17:49
5 | # @File : test_api.py
6 | # @Project : apitest
7 | # @Mail : 1203069758@qq.com
8 | import os
9 | import pytest
10 | import xmltodict
11 | from rdfile.rdini import read_ini
12 | from rdfile.rdExcel import read_excel
13 | from Common.Base_test import ApiRequest
14 | from Common.Login import cookie
15 | from Logs.log import log1
16 |
17 |
18 | class TestYongHong:
19 |
20 |
21 | def setup_class(self):
22 | print('开始测试')
23 |
24 |
25 | def teardown_class(self):
26 | print('结束测试')
27 |
28 | def test_api(self):
29 | token = cookie().login()
30 | ip = read_ini('url', 'ip')
31 | port = read_ini('url', 'port')
32 | datatable = read_excel('a.xls', 'Sheet1')
33 | data = datatable.getExceldatas()
34 | # 读出来是个列表内包含字典
35 |
36 |
37 | # 因为第一行是excel表头,从第二行开始获取
38 | for i in range(1, datatable.get_nrows()):
39 | path = data[i]['path']
40 | method = data[i]['method']
41 | headers = data[i]['headers']
42 | body = data[i]['data']
43 | # 前面是从excel取得值
44 | url = 'http://' + ip + ':' + port + path + token
45 | checkpoint = data[i]['check']
46 |
47 | try:
48 | res = ApiRequest().send_requests(method=method, url=url, headers=eval(headers), data=eval(body))
49 | resDict = xmltodict.parse(res.text)
50 | # assert resDict['results']['result']['level'] == '1'
51 | assert checkpoint in res.text, '响应内容错误'
52 | log1.info("正在测试的接口编号是:%s,名称是%s" % (data[i]['c_bh'], data[i]['name']))
53 | except Exception:
54 | log1.error("当前接口运行有误,其编号是%s" % data[i]['c_bh'])
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | if __name__ == '__main__':
63 | # os.system(r'del /f /q ..\Logs\ALL_Logs')
64 | # os.system(r'del /f /q ..\Logs\ERROR_Logs') # 先删除旧日志
65 | pytest.main(['-s', '-v', 'test_two.py', '--clean-alluredir', '--alluredir', '../report/allure_result'])
66 | os.system(r'allure serve ../report/allure_result')
67 | # 等同于在dos执行:pytest -s -v --clean-alluredir --alluredir ../report/allure_result
68 | # 等同于在dos执行: allure serve ../report/allure_result
69 |
--------------------------------------------------------------------------------