├── InterAutoTest_W
├── data
│ ├── __init__.py
│ ├── testdata.xlsx
│ └── testlogin.yml
├── logs
│ └── __init__.py
├── utils
│ ├── __init__.py
│ ├── YamlUtil.py
│ ├── AssertUtil.py
│ ├── ExcelUtil.py
│ ├── RequestsUtil.py
│ ├── LogUtil.py
│ └── MysqlUtil.py
├── common
│ ├── __init__.py
│ ├── ExcelConfig.py
│ ├── ExcelData.py
│ └── Base.py
├── config
│ ├── __init__.py
│ ├── db_conf.yml
│ ├── conf.yml
│ └── Conf.py
├── report
│ ├── __init__.py
│ ├── assets
│ │ └── style.css
│ └── report.html
├── testcase
│ ├── __init__.py
│ ├── t_yaml
│ │ ├── __init__.py
│ │ ├── yaml_demo.py
│ │ └── data.yml
│ ├── t_allure
│ │ ├── __init__.py
│ │ └── allure_demo.py
│ ├── t_excel
│ │ ├── __init__.py
│ │ ├── testdata.xlsx
│ │ └── excel_demo.py
│ ├── t_pytest
│ │ ├── __init__.py
│ │ ├── pytest_one.py
│ │ ├── pytest_more.py
│ │ ├── pytest_class.py
│ │ ├── pytest_demo.py
│ │ ├── pytest_func.py
│ │ └── report
│ │ │ ├── assets
│ │ │ └── style.css
│ │ │ └── report.html
│ ├── test_log
│ │ ├── __init__.py
│ │ ├── log_demo.py
│ │ └── log_file_demo.py
│ ├── T_requests.py
│ ├── test_login.py
│ ├── test_mall.py
│ └── test_excel_case.py
├── run.py
├── pytest.ini
└── .vscode
│ └── settings.json
├── 美多商城-接口文档.PDF
├── image
└── 代码测试结构.jpg
├── requirement.txt
├── LICENSE
├── .gitignore
└── README.md
/InterAutoTest_W/data/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/InterAutoTest_W/logs/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/InterAutoTest_W/utils/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/InterAutoTest_W/common/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/InterAutoTest_W/config/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/InterAutoTest_W/report/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/t_yaml/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/t_allure/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/t_excel/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/t_pytest/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/test_log/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/美多商城-接口文档.PDF:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chengfeiZhou/testpy/HEAD/美多商城-接口文档.PDF
--------------------------------------------------------------------------------
/image/代码测试结构.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chengfeiZhou/testpy/HEAD/image/代码测试结构.jpg
--------------------------------------------------------------------------------
/InterAutoTest_W/data/testdata.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chengfeiZhou/testpy/HEAD/InterAutoTest_W/data/testdata.xlsx
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/T_requests.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | import requests
3 | r = requests.get('http://www.baidu.com')
4 | print(r)
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/t_excel/testdata.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chengfeiZhou/testpy/HEAD/InterAutoTest_W/testcase/t_excel/testdata.xlsx
--------------------------------------------------------------------------------
/InterAutoTest_W/config/db_conf.yml:
--------------------------------------------------------------------------------
1 | db_1:
2 | host: "211.103.136.242"
3 | port: 7090
4 | user: "test"
5 | password: "test123456"
6 | database: "meiduo"
7 | charset: "utf8"
8 |
--------------------------------------------------------------------------------
/InterAutoTest_W/config/conf.yml:
--------------------------------------------------------------------------------
1 | BASE:
2 | log_level: 'debug'
3 | log_extension: '.log'
4 |
5 | test:
6 | url: "http://211.103.136.242:8064"
7 | case_file: "testdata.xlsx"
8 | case_sheet: 0
--------------------------------------------------------------------------------
/InterAutoTest_W/run.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | import os
3 | import pytest
4 | from config import Conf
5 |
6 | if __name__ == "__main__":
7 | report_path = Conf._report_path()
8 | pytest.main(['-s', '--alluredir', report_path+'/reslut'])
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/t_yaml/yaml_demo.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """
3 | 1. 创建yaml文件
4 | 2. 读取yaml文件
5 | 3. 输出yaml文件
6 | """
7 | import yaml
8 |
9 | with open('./data.yml', 'r') as f:
10 | r = yaml.safe_load(f)
11 |
12 | print(r)
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/InterAutoTest_W/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | # addopts = -s --html=./report/report.html --reruns 3 --reruns-delay=2
3 | # addopts = -s --html=./report/report.html
4 |
5 | # allure setting
6 | addopts = -s
7 |
8 |
9 | testpaths = testcases
10 | python_files = test*.py
11 | python_classes = Test*
12 | python_functions = test*
13 |
14 |
--------------------------------------------------------------------------------
/InterAutoTest_W/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "python.testing.pytestArgs": [
3 | "testcase"
4 | ],
5 | "python.testing.unittestEnabled": false,
6 | "python.testing.nosetestsEnabled": false,
7 | "python.testing.pytestEnabled": true,
8 | "python.pythonPath": "C:\\Develop\\Python\\Anaconda3\\envs\\testpy\\python.exe"
9 | }
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/test_log/log_demo.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | # 1.导入logging包
3 | import logging
4 | # 2.设置配置信息
5 | logging.basicConfig(level=logging.INFO, format="%(asctime)s-%(name)s-%(levelname)s-%(message)s")
6 | # 3. 定义日志名称:get_logger
7 | logger = logging.getLogger('log_demo')
8 | # 4. info,debug
9 | logger.info('info')
10 | logger.debug('debug')
11 | logger.warning('warning')
12 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/t_pytest/pytest_one.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """
3 | 1. 创建类和测试方法
4 | 2. 创建数据
5 | 3. 创建参数化
6 | 4.运行
7 | """
8 | import pytest
9 |
10 | class TestClass():
11 | data_list = ['xiaoming', 'xiaohong']
12 |
13 | @pytest.mark.parametrize('name',data_list)
14 | def test_a(self, name):
15 | print('test_a')
16 | print(name)
17 | assert 1
18 |
19 |
20 | if __name__ == "__main__":
21 | pytest.main(['-s','pytest_one.py'])
22 |
--------------------------------------------------------------------------------
/InterAutoTest_W/data/testlogin.yml:
--------------------------------------------------------------------------------
1 |
2 | ---
3 | 'case_name': "success login"
4 | 'url': 'http://211.103.136.242:8064/authorizations/'
5 | 'data':
6 | 'username': "python"
7 | 'password': "12345678"
8 | 'expect': "'username': 'python', 'user_id': 1"
9 | ---
10 | 'case_name': "failure login"
11 | 'url': 'http://211.103.136.242:8064/authorizations/'
12 | 'data':
13 | 'username': "test123456"
14 | 'password': "1231111"
15 | 'expect': "'username': 'python', 'user_id': 1"
16 |
17 |
18 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/t_pytest/pytest_more.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """
3 | 1. 创建类和测试方法
4 | 2. 创建数据
5 | 3. 创建参数化
6 | 4.运行
7 | """
8 | import pytest
9 |
10 | class TestClass():
11 | data_list = [('xiaoming', '12345'),('xiaohong', '56789')]
12 |
13 | @pytest.mark.parametrize(('name','psw'),data_list)
14 | def test_a(self, name,psw):
15 | print('test_a')
16 | print(name,psw)
17 | assert 1
18 |
19 |
20 | if __name__ == "__main__":
21 | pytest.main(['-s','pytest_more.py'])
--------------------------------------------------------------------------------
/requirement.txt:
--------------------------------------------------------------------------------
1 | allure-pytest==2.8.6
2 | allure-python-commons==2.8.6
3 | atomicwrites==1.3.0
4 | attrs==19.3.0
5 | certifi==2019.9.11
6 | chardet==3.0.4
7 | colorama==0.4.1
8 | idna==2.8
9 | more-itertools==7.2.0
10 | packaging==19.2
11 | pluggy==0.13.1
12 | py==1.8.0
13 | PyMySQL==0.9.3
14 | pyparsing==2.4.5
15 | pytest==5.3.1
16 | pytest-html==2.0.1
17 | pytest-metadata==1.8.0
18 | pytest-rerunfailures==8.0
19 | PyYAML==5.1.2
20 | requests==2.22.0
21 | six==1.13.0
22 | urllib3==1.25.7
23 | wcwidth==0.1.7
24 | wincertstore==0.2
25 | xlrd==1.2.0
26 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/t_yaml/data.yml:
--------------------------------------------------------------------------------
1 | # name: "test_yaml"
2 | # result: "success"
3 |
4 | # - 12
5 | # - 32
6 | # - 33
7 |
8 |
9 | # person1:
10 | # name: xiaoming
11 | # age: 18
12 | # person2:
13 | # name: xiaohong
14 | # age: 16
15 |
16 | # person:
17 | # - "a"
18 | # - "b"
19 | # - c
20 |
21 |
22 | # -
23 | # - 1
24 | # - 2
25 | # - 3
26 | # - "b"
27 | # - c
28 | # -
29 | # - 6
30 | # - 7
31 | # - 8
32 |
33 | -
34 | name: xiaoming
35 | age: 18
36 | - 2
37 | - 3
38 | -
39 | name: xiaohong
40 | age: 16
41 |
42 |
43 |
--------------------------------------------------------------------------------
/InterAutoTest_W/common/ExcelConfig.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 | # 定义类
4 | # 定义列属性
5 |
6 | class DataConfig():
7 | # 用例属性:
8 | case_id = "用例ID"
9 | case_model = "模块"
10 | case_name = "接口名称"
11 | url = "请求URL"
12 | pre_exec = "前置条件"
13 | method = "请求类型"
14 | params_type = "请求参数类型"
15 | params = "请求参数"
16 | expect_result = "预期结果"
17 | actual_result = "实际结果"
18 | beizhu = "备注"
19 | is_run = "是否运行"
20 | headers = "headers"
21 | cookies = "cookies"
22 | code = "status_code"
23 | db_verify = "数据库验证"
24 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/t_pytest/pytest_class.py:
--------------------------------------------------------------------------------
1 | #coding=utf-8
2 |
3 | """
4 | 1.定义类;
5 | 2.创建测试方法test开头
6 | 3.创建setup_class, teardown_class
7 | 4.运行查看结果
8 | """
9 | import pytest
10 |
11 | class TestClass():
12 | def test_a(self):
13 | print('test_a')
14 |
15 | def test_b(self):
16 | print('test_b')
17 |
18 | def setup_class(self):
19 | print('------setup_class------')
20 |
21 | def teardown_class(self):
22 | print('------teardown_class------')
23 |
24 | if __name__ == "__main__":
25 | pytest.main(['-s', 'pytest_class.py'])
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/t_pytest/pytest_demo.py:
--------------------------------------------------------------------------------
1 | #coding=utf-8
2 |
3 | # 1. 创建简单的测试方法
4 | # 2. pytest运行
5 | # 2.1 idea中直接执行
6 | # 2.2 命令行执行
7 | import pytest
8 |
9 | # 创建普通的方法
10 | def func(x):
11 | return x+1
12 |
13 |
14 | # 创建pytest断言的方法
15 | def test_a():
16 | print("---test_a---")
17 | assert func(3) == 5 # 断言失败
18 |
19 | # 使用装饰器,控制单个测试用例的运行情况
20 | @pytest.mark.flaky(reruns=3, reruns_delay=2)
21 | def test_b():
22 | print('---test_b---')
23 | assert func(3) == 4 # 断言成功
24 |
25 | # 代码直接执行
26 | if __name__ == "__main__":
27 | pytest.main(["pytest_demo.py"])
28 |
29 |
30 | # 命令行执行:
31 | # pytest pytest_demo.py
32 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/t_excel/excel_demo.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 | """
4 | 1. 导入包, xlrd(python自带)
5 | 2. 创建workbook对象
6 | 3. sheet对象
7 | 4. 获取行数和列数
8 | 5. 读取每行的内容
9 | 6. 读取每列的内容
10 | 7. 读取固定列的内容
11 | """
12 | import xlrd
13 | book = xlrd.open_workbook('./testdata.xlsx')
14 | # 获取表的两种方式:
15 | # 索引
16 | # sheet = book.sheet_by_index(0)
17 | # 名称
18 | sheet = book.sheet_by_name('美多商城接口测试')
19 |
20 | rows = sheet.nrows # 行数
21 | cols = sheet.ncols # 列数
22 | print(f"rows:{rows}, cols:{cols}")
23 |
24 | # 获取每行数据
25 | for r in range(rows):
26 | r_values = sheet.row_values(r)
27 | print(r_values)
28 |
29 | # 获取每列数据
30 | for c in range(cols):
31 | c_values = sheet.col_values(c)
32 | print(c_values)
33 |
34 | # 读取固定列的内容
35 | v = sheet.cell(1,2)
36 | print(v)
--------------------------------------------------------------------------------
/InterAutoTest_W/utils/YamlUtil.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 | # 1. 创建类
4 | # 2. 初始化,文件是否存在
5 | # 3. yaml读取
6 |
7 | import os
8 | import yaml
9 |
10 | class YamlReader():
11 | def __init__(self, yaml_p):
12 | if os.path.exists(yaml_p):
13 | self.yaml_p = yaml_p
14 | else:
15 | raise FileNotFoundError("文件不存在")
16 | self._data = None
17 | self._data_all = None
18 |
19 | def data(self):
20 | # 读取单个文档
21 | if not self._data:
22 | with open(self.yaml_p, 'r') as f:
23 | self._data = yaml.safe_load(f)
24 | return self._data
25 |
26 | def data_all(self):
27 | # 读取单个文档
28 | if not self._data:
29 | with open(self.yaml_p, 'r') as f:
30 | self._data_all = list(yaml.safe_load_all(f))
31 | return self._data_all
32 |
33 |
34 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/test_log/log_file_demo.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | import logging
3 |
4 |
5 | # 1. 设置logger名称
6 | logger = logging.getLogger('log_file_demo')
7 | # 2. 设置log级别
8 | logger.setLevel(logging.INFO)
9 | # 3. 创建handler, 用于输出控制台或写入文件
10 | # 输出到控制台
11 | fh_stream = logging.StreamHandler()
12 | # 写入文件
13 | fh_file = logging.FileHandler('./test.log')
14 | # 4. 设置日志级别
15 | fh_stream.setLevel(logging.INFO)
16 | fh_file.setLevel(logging.INFO)
17 | # 5. 定义handler的输出格式
18 | formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(message)s')
19 | fh_stream.setFormatter(formatter)
20 | fh_file.setFormatter(formatter)
21 | # 6. 添加handler
22 | logger.addHandler(fh_stream)
23 | logger.addHandler(fh_file)
24 |
25 | # 7. 运行
26 | logger.info('this is a info')
27 | logger.debug('this is a debug')
28 |
29 | # 2019-11-20 23:29:13,977 log_file_demo INFO this is a info
30 | # 因为debug的级别小于info,所以不输出debug
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/test_login.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 | # 1. 获取测试用例的列表
4 | # 获取testlogin.yml文件路径
5 | # 使用工具类来读取多个文档的内容
6 | # 2. 参数化执行测试用例
7 |
8 | import os
9 | import sys
10 | sys.path.append("../")
11 | import pytest
12 | from config import Conf
13 | from config.Conf import ConfigYaml
14 | from utils.YamlUtil import YamlReader
15 | from utils.RequestsUtil import Request
16 |
17 | test_file = os.path.join(Conf.get_data_path(), 'testlogin.yml')
18 | print(test_file)
19 |
20 | data_list = YamlReader(test_file).data_all()
21 | print(data_list)
22 |
23 | @pytest.mark.parametrize("login", data_list)
24 | def test_yaml(login):
25 | """
26 | 执行测试用例
27 | """
28 | uri = login['url']
29 | print(uri)
30 | data = login['data']
31 | print(data)
32 | request = Request(ConfigYaml().get_config_url())
33 | res = request.post(uri, json=data)
34 | print(res)
35 |
36 |
37 | if __name__ == "__main__":
38 | pytest.main(['test_login.py'])
39 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/t_allure/allure_demo.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 | import pytest
4 | import allure
5 |
6 | @allure.feature('接口测试, 这是一个一级标签')
7 | class TestAllure():
8 | # 定义测试方法
9 | @allure.title('测试用例标题1')
10 | @allure.description('执行测试用例1的结果是:test_1')
11 | @allure.stroy("这是一个二级标签:test1")
12 | @allure.severity(allure.severity.CRITICAL)
13 | def test_1(self):
14 | print("test_1")
15 |
16 | @allure.title('测试用例标题2')
17 | @allure.description('执行测试用例2的结果是:test_2')
18 | @allure.stroy("这是一个二级标签:test1")
19 | @allure.severity(allure.severity.BLOCKER)
20 | def test_2(self):
21 | print("test_2")
22 |
23 | @allure.title('测试用例标题3')
24 | @allure.description('执行测试用例3的结果是:test_3')
25 | @allure.stroy("这是一个二级标签:test3")
26 | def test_3(self):
27 | print("test_3")
28 |
29 | @pytest.mark.parametrize("case",['case1', 'case2', 'case3'])
30 | def test_4(self, case):
31 | print(f"test4: {case}")
32 | allure.dynamic.title(case)
33 |
34 |
35 | if __name__ == "__main__":
36 | pytest.main(['allure_demo.py'])
37 |
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 zhou_chengfei
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/InterAutoTest_W/common/ExcelData.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 | # 1. 使用excel工具类, 获取结果list
4 | # 2. 列"是否运行内容", y
5 | # 3. 保存要执行结果, 放到新的列表中
6 | import sys
7 | sys.path.append('../')
8 | from utils.ExcelUtil import ExcelReader
9 | from common.ExcelConfig import DataConfig
10 |
11 | class Data():
12 | def __init__(self, excel_file, sheet_by):
13 | self.reader = ExcelReader(excel_file, sheet_by)
14 |
15 | def get_run_data(self):
16 | """
17 | 根据"是否运行"列,获取执行测试用例
18 | """
19 | run_list = []
20 | for line in self.reader.data():
21 | if str(line[DataConfig().is_run]).lower() == 'y':
22 | run_list.append(line)
23 | return run_list
24 |
25 | def get_case_list(self):
26 | """
27 | 获取全部的测试用例
28 | """
29 | run_list = [line for line in self.reader.data()]
30 | return run_list
31 |
32 | def get_case_pre(self, pre):
33 | """
34 | 根据前置条件,从全部测试用例中返回前置用例
35 | """
36 | # 获取前部测试用例
37 | # 判断需前置执行的用例
38 | run_list = self.get_case_list()
39 | for line in run_list:
40 | if pre in dict(line).values():
41 | return line
42 | return None
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/InterAutoTest_W/utils/AssertUtil.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """
3 | 1. 定义封装类;
4 | 2. 初始化数据,日志
5 | 3. code相等
6 | 4. body相等
7 | 5.body包含
8 | """
9 | import sys
10 | sys.path.append('../')
11 | import json
12 | from utils.LogUtil import my_log
13 |
14 | class AssertUtil():
15 |
16 | def __init__(self):
17 | self.log = my_log('AssertUtil')
18 |
19 | def assert_code(self, code, expected_code):
20 | """
21 | 验证返回状态码
22 | """
23 | try:
24 | assert int(code) == int(expected_code)
25 | return True
26 | except Exception as e:
27 | self.log.error(f'code error, code is {code}, expected_code is {expected_code}')
28 | raise
29 |
30 | def assert_body(self, body, expected_body):
31 | """
32 | 验证返回结果内容相等
33 | """
34 | try:
35 | assert body == expected_body
36 | return True
37 | except Exception as e:
38 | self.log.error(f'body error, body is {body}, expected_body is {expected_body}')
39 | raise
40 |
41 | def assert_in_body(self, body, expected_body):
42 | """
43 | 验证返回结果是否包含期望的结果
44 | """
45 | try:
46 | body = json.dumps(body)
47 | assert expected_body in body
48 | return True
49 | except Exception as e:
50 | self.log.error(f'body error, body not in expected_body, body is {body}, expected_body is {expected_body}')
51 | raise
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/t_pytest/pytest_func.py:
--------------------------------------------------------------------------------
1 | #coding=utf-8
2 |
3 | """
4 | 1.定义类;
5 | 2.创建测试方法test开头
6 | 3.创建setup, teardown
7 | 4.运行查看结果
8 | """
9 | import pytest
10 |
11 | class TestFcun():
12 | def test_a(self):
13 | print('test_a')
14 |
15 | def test_b(self):
16 | print('test_b')
17 |
18 | def setup(self):
19 | print('------setup------')
20 |
21 | def teardown(self):
22 | print('------teardown------')
23 |
24 | if __name__ == "__main__":
25 | pytest.main(['-s', 'pytest_func.py'])
26 |
27 | """
28 | PS E:\学习\测试\InterAutoTest_W\testcase\t_pytest> python pytest_func.py
29 | =========================================================================== test session starts ===========================================================================
30 | platform win32 -- Python 3.7.3, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
31 | rootdir: E:\学习\测试\InterAutoTest_W, inifile: pytest.ini
32 | plugins: remotedata-0.3.1, openfiles-0.3.2, doctestplus-0.3.0, arraydiff-0.3
33 | collected 2 items
34 |
35 | pytest_func.py ------setup------
36 | test_a
37 | .------teardown------
38 | ------setup------
39 | test_b
40 | .------teardown------
41 |
42 |
43 | ======================================================================== 2 passed in 0.08 seconds =========================================================================
44 |
45 |
46 | """
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/InterAutoTest_W/utils/ExcelUtil.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 | # 目的: 参数化, pytest list
4 |
5 | # 1. 验证文件是否存在,存在读取,不存在错报
6 | # 2. 读取sheet方式, 名称,索引
7 | # 3. 读取sheet内容
8 | # 返回list, 字典
9 | # 格式: [{'a':"a1",'b':" b1"}, {'a':"a2",'b':"b2"}]
10 | # 4. 结果返回
11 |
12 | import os
13 | import xlrd
14 |
15 |
16 | # 自定义异常
17 | class SheetTypeError(object):
18 | pass
19 |
20 | class ExcelReader():
21 | def __init__(self, excel_file, sheet_by):
22 | if os.path.exists(excel_file):
23 | self.excel_file = excel_file
24 | self.sheet_by = sheet_by
25 | self.data_list = []
26 | else:
27 | raise FileNotFoundError("文件不存在")
28 |
29 | def data(self):
30 | if self.data_list:
31 | return self.data_list
32 |
33 | workbook = xlrd.open_workbook(self.excel_file)
34 |
35 | if type(self.sheet_by) not in [str,int]:
36 | raise SheetTypeError("参数错误")
37 | elif type(self.sheet_by) == int:
38 | sheet = workbook.sheet_by_index(self.sheet_by)
39 | elif type(self.sheet_by) == str:
40 | sheet = workbook.sheet_by_name(self.sheet_by)
41 |
42 | # 获取首行信息
43 | title = sheet.row_values(0)
44 | for r in range(1, sheet.nrows):
45 | self.data_list.append(dict(zip(title,sheet.row_values(r))))
46 | # print(self.data_list)
47 | return self.data_list
48 |
49 | if __name__ == "__main__":
50 | excel_reader = ExcelReader('../data/testdata.xlsx',"美多商城接口测试")
51 | print(excel_reader.data())
52 |
--------------------------------------------------------------------------------
/.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 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 | .pytest_cache/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 | db.sqlite3
58 |
59 | # Flask stuff:
60 | instance/
61 | .webassets-cache
62 |
63 | # Scrapy stuff:
64 | .scrapy
65 |
66 | # Sphinx documentation
67 | docs/_build/
68 |
69 | # PyBuilder
70 | target/
71 |
72 | # Jupyter Notebook
73 | .ipynb_checkpoints
74 |
75 | # pyenv
76 | .python-version
77 |
78 | # celery beat schedule file
79 | celerybeat-schedule
80 |
81 | # SageMath parsed files
82 | *.sage.py
83 |
84 | # Environments
85 | .env
86 | .venv
87 | env/
88 | venv/
89 | ENV/
90 | env.bak/
91 | venv.bak/
92 |
93 | # Spyder project settings
94 | .spyderproject
95 | .spyproject
96 |
97 | # Rope project settings
98 | .ropeproject
99 |
100 | # mkdocs documentation
101 | /site
102 |
103 | # mypy
104 | .mypy_cache/
105 |
--------------------------------------------------------------------------------
/InterAutoTest_W/utils/RequestsUtil.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 | # 1.创建封装方法
4 | # 2.发送requests请求
5 | # 3.获取结果相应内容
6 | # 4.内容存储到字典
7 | # 5.字典返回
8 |
9 | import requests
10 | from config.Conf import ConfigYaml
11 |
12 | def r_get(url, json=None, headers=None):
13 | r = requests.get(url,json=json, headers=headers)
14 |
15 | code = r.status_code
16 | try:
17 | body = r.json()
18 | except:
19 | body = r.text
20 |
21 | res = {
22 | 'code':code,
23 | 'body':body
24 | }
25 |
26 | return res
27 |
28 |
29 | def r_post(url, json=None, headers=None):
30 | r = requests.post(url,json=json, headers=headers)
31 |
32 | code = r.status_code
33 | try:
34 | body = r.json()
35 | except:
36 | body = r.text
37 |
38 | res = {
39 | 'code':code,
40 | 'body':body
41 | }
42 |
43 | return res
44 |
45 | # 重构
46 | class Request():
47 | def __init__(self,url=ConfigYaml().get_config_url() ):
48 | self.url = url
49 |
50 | # 定义公共方法:
51 | def request_api(self, uri, method='get', data=None,json=None, headers=None,cookies=None):
52 | if method == 'get':
53 | r = requests.get(self.url+uri, data=data, json=json, headers=headers, cookies=cookies)
54 | elif method == 'post':
55 | r = requests.post(self.url+uri, data=data, json=json, headers=headers, cookies=cookies)
56 |
57 | code = r.status_code
58 | try:
59 | body = r.json()
60 | except:
61 | body = r.text
62 | res = {
63 | 'code':code,
64 | 'body':body
65 | }
66 | return res
67 |
68 | # 重构get方法
69 | def get(self, url,**kwargs):
70 | return self.request_api(url,**kwargs)
71 |
72 | def post(self, url,**kwargs):
73 | return self.request_api(url,method='post',**kwargs)
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/InterAutoTest_W/utils/LogUtil.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 | # 封装工具类
4 | # 1.创建类
5 | # 2.定义参数
6 | # 输出文件名称,Loggername,日志级别
7 | # 3.编写输出到控制台或文件
8 | import sys
9 | sys.path.append('../')
10 |
11 | import logging
12 | import datetime, os
13 | from config import Conf
14 | from config.Conf import ConfigYaml
15 |
16 | log_l = {
17 | "info": logging.INFO,
18 | "debug": logging.DEBUG,
19 | "warning": logging.WARNING,
20 | "error": logging.ERROR
21 | }
22 |
23 | class Logger():
24 | def __init__(self, log_file, log_name, log_level):
25 | self.log_file = log_file
26 | self.log_name = log_name
27 | self.log_level = log_level
28 |
29 | # 设置log名称
30 | self.logger = logging.getLogger(self.log_name)
31 | # 设置log级别
32 | self.logger.setLevel(log_l[self.log_level])
33 | # 判断handler是否存在
34 | if not self.logger.handlers:
35 | # 输出到控制台
36 | fh_stream = logging.StreamHandler()
37 | fh_stream.setLevel(log_l[self.log_level])
38 | formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(message)s')
39 | fh_stream.setFormatter(formatter)
40 | # 输出到文件
41 | fh_file = logging.FileHandler(self.log_file)
42 | fh_file.setLevel(log_l[self.log_level])
43 | fh_file.setFormatter(formatter)
44 | # 添加到handler
45 | self.logger.addHandler(fh_stream)
46 | self.logger.addHandler(fh_file)
47 |
48 |
49 | # 1.初始化参数数据
50 | # 日志文件名称
51 | log_path = Conf.get_log_path()
52 | current_time = datetime.datetime.now().strftime('%Y-%m-%d')
53 | log_extension = ConfigYaml().get_conf_log_extension()
54 | logfile = os.path.join(log_path,current_time+log_extension)
55 | # print(logfile)
56 |
57 | # 日志文件级别
58 | loglevel = ConfigYaml().get_conf_log()
59 | # print(loglevel)
60 |
61 | # 2. 对外方法: 初始化log工具类, 提供其他类使用
62 | def my_log(log_name = __file__):
63 | return Logger(log_file=logfile, log_name=log_name, log_level=loglevel).logger
64 |
65 | if __name__ == "__main__":
66 | my_log().debug("this is a debug")
67 |
--------------------------------------------------------------------------------
/InterAutoTest_W/config/Conf.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | import os
3 | import sys
4 | sys.path.append('../')
5 | from utils.YamlUtil import YamlReader
6 | # 1. 获取项目基本目录
7 | # 1.2 获取当前项目的绝对路径
8 | current = os.path.abspath(__file__)
9 | BASE_DIR = os.path.dirname(os.path.dirname(current))
10 | # print(current, BASE_DIR)
11 | # 1.3 定义config目录的路径
12 | _config_path = BASE_DIR + os.sep + "config"
13 | _data_path = BASE_DIR + os.sep + "data"
14 | # 1.4 定义conf.yml的文件路径
15 | _config_file = _config_path + os.sep + 'conf.yml'
16 |
17 | # 定义logs文件路径
18 | _log_path = BASE_DIR + os.sep + "logs"
19 |
20 | # 定义db_conf.yml文件路径
21 | _db_config_file = _config_path + os.sep + 'db_conf.yml'
22 |
23 | # 配置report路径
24 | _report_path = BASE_DIR + os.sep + "report"
25 |
26 | def get_report_path():
27 | return _ewport_path
28 |
29 | def get_config_path():
30 | return _config_path
31 |
32 | def get_data_path():
33 | return _data_path
34 |
35 | def get_config_file():
36 | return _config_file
37 |
38 | def get_log_path():
39 | """
40 | 获取log文件路径
41 | """
42 | return _log_path
43 |
44 | def get_db_conf_file():
45 | """
46 | 获取db_conf文件路径
47 | """
48 | return _db_config_file
49 |
50 |
51 | # 2. 读取配置文件
52 | class ConfigYaml():
53 | def __init__(self):
54 | self.config = YamlReader(get_config_file()).data()
55 | self.db_config = YamlReader(get_db_conf_file()).data()
56 |
57 | def get_excel_file(self):
58 | """
59 | 获取excel测试用例文件名称
60 | """
61 | return self.config['BASE']['test']['case_file']
62 |
63 |
64 | def get_excel_sheet(self):
65 | """
66 | 获取excel测试用例文件sheet名称
67 | """
68 | return self.config['BASE']['test']['case_sheet']
69 |
70 | # 获取需要的信息
71 | def get_config_url(self):
72 | return self.config['BASE']['test']['url']
73 |
74 | def get_conf_log(self):
75 | """
76 | 获取日志级别
77 | """
78 | return self.config['BASE']['log_level']
79 |
80 | def get_conf_log_extension(self):
81 | return self.config['BASE']['log_extension']
82 |
83 | def get_db_conf_info(self, db_alias):
84 | """
85 | 根据db_alias获取数据库相关参数
86 | """
87 | return self.db_config[db_alias]
88 |
89 | if __name__ == "__main__":
90 | conf_read = ConfigYaml()
91 | print(conf_read)
92 | print(conf_read.get_conf_log())
93 | print(conf_read.get_conf_log_extension())
94 | print(conf_read.get_db_conf_info('db_1'))
95 | # print(conf_read.get_excel_file())
96 | # print(conf_read.get_excel_sheet())
97 |
--------------------------------------------------------------------------------
/InterAutoTest_W/utils/MysqlUtil.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """
3 | 1. 创建封装类
4 | 2.初始化数据,连接数据库,光标对象
5 | 3. 创建查询,执行方法
6 | 4. 关闭对象
7 | """
8 | import sys
9 | sys.path.append('../')
10 | import pymysql
11 | import functools
12 |
13 | from utils.LogUtil import my_log
14 |
15 | class Mysql():
16 | def __init__(self,host,user,password,database,port=3306,charset='utf8mb4'):
17 | self.cnn = pymysql.connect(
18 | host=host,
19 | port=port,
20 | user=user,
21 | password=password,
22 | database=database,
23 | charset=charset
24 | )
25 | self.cursor = self.cnn.cursor(cursor=pymysql.cursors.DictCursor) # 结果使用dict返回
26 | self.log = my_log()
27 |
28 | def __del__(self):
29 | try:
30 | self.cnn.close()
31 | except Exception as e:
32 | pass
33 |
34 | try:
35 | self.cursor.close()
36 | except Exception as e:
37 | pass
38 |
39 | def fetch_one(self, sql):
40 | """
41 | 查询一个对象
42 | """
43 | self.cursor.execute(sql)
44 | return self.cursor.fetchone()
45 |
46 | def fetch_all(self, sql):
47 | """
48 | 查询全部对象
49 | """
50 | self.cursor.execute(sql)
51 | return self.cursor.fetchall()
52 |
53 | def exec(self,sql):
54 | """
55 | 执行操作
56 | """
57 | try:
58 | self.cursor.execute(sql)
59 | self.cursor.commit()
60 | except Exception as e:
61 | self.cnn.rollback()
62 | self.log.error(e)
63 | return False
64 | return True
65 |
66 | if __name__ == "__main__":
67 | mysql = Mysql(
68 | host='211.103.136.242',
69 | port=7090,
70 | user='test',
71 | password='test123456',
72 | database='meiduo',
73 | charset='utf8',
74 | )
75 | res = mysql.fetch_all('select * from tb_uders')
76 | print(res)
77 |
78 |
79 | """
80 | 1. 创建db_conf.yml
81 | 2. 编写数据库基本信息
82 | 3. 重构Conf.py
83 | 4. 执行
84 | """
85 |
86 |
87 | # cnn = pymysql.connect(
88 | # host='211.103.136.242',
89 | # port=7090,
90 | # user='test',
91 | # password='test123456',
92 | # database='meiduo',
93 | # charset='utf8',
94 | # )
95 |
96 | # with cnn.cursor() as cursor:
97 | # sql_str = 'select * from tb_users'
98 | # cursor.execute(sql_str)
99 | # res = cursor.fetchall()
100 | # print(res)
101 |
102 | # cnn.close()
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/InterAutoTest_W/common/Base.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | # 1.定义一个方法init_db
3 | # 2.初始化数据库信息, 通过配置文件来完成
4 | # 3.初始化mysql对象
5 | import sys
6 | sys.path.append('../')
7 | import json
8 | import re
9 | import subprocess
10 | from config.Conf import ConfigYaml
11 | from utils.MysqlUtil import Mysql
12 | from utils.AssertUtil import AssertUtil
13 | from utils.LogUtil import my_log
14 |
15 |
16 | p_data = r'\${(.*)}\$'
17 | log = my_log()
18 | report_path = ""
19 | def init_db(db_alias):
20 | db_init = ConfigYaml().get_db_conf_info(db_alias)
21 | host = db_init.get('host', '127.0.0.1')
22 | port = int(db_init.get('port', 3306))
23 | user = db_init.get('user')
24 | database = db_init.get('database')
25 | password = db_init.get('password')
26 | charset = db_init.get('charset', 'utf8')
27 |
28 | conn = Mysql(host=host,port=port,user=user,password=password,database=database,charset=charset)
29 | return conn
30 |
31 | def assert_db(db_name, res_body, db_verify):
32 | """
33 | 数据库验证
34 | """
35 | assert_util = AssertUtil()
36 | sql = init_db(db_name)
37 | db_res = sql.fetch_one(db_verify)
38 | log.debug(f"数据库查询结果:{str(db_res)}")
39 | for db_k,db_v in db_res.items():
40 | res_line = res_body[db_k]
41 | assert_util.assert_body(res_line, db_v)
42 |
43 | def json_parse(data):
44 | """
45 | 格式化数据
46 | """
47 | return json.loads(data) if data else data
48 |
49 | def res_find(data, pattern_data=p_data):
50 | """
51 | 查询匹配
52 | """
53 | pattern = re.compile(pattern_data)
54 | res = pattern.findall(data)
55 | return res
56 |
57 |
58 | def res_sub(data, replace, pattern_data=p_data):
59 | """
60 | 请求参数替换
61 | :param data: 源字符串
62 | :param replace: 替换内容
63 | :param pattern_data: 匹配规则
64 | """
65 | pattern = re.compile(pattern_data)
66 | res = pattern.findall(data)
67 | if res:
68 | return re.sub(pattern_data,replace, data)
69 | else:
70 | return res
71 |
72 | def params_find(headers, cookies):
73 | """
74 | 验证请求中是否有${}$需要结果关联
75 |
76 | """
77 | if "${" in headers:
78 | headers = res_find(headers)
79 | if "${" in cookies:
80 | cookies = res_find(cookies)
81 |
82 | return headers, cookies
83 |
84 | def allure_report(report_path):
85 | allure_cmd = f"allure generate {report_path}/result -o {report_path}/html --clean"
86 | log.info(f"报告地址:{report_path}")
87 | try:
88 | subprocess.call(allure_cmd, shell=True)
89 | except Exception as e:
90 | log.error(e)
91 |
92 |
93 | if __name__ == "__main__":
94 | # conn = init_db('db_1')
95 | # print(conn)
96 |
97 | print(res_find('{"Authorization": "JWT ${token}$"}', r'\${(.*)}\$'))
98 | print(res_sub('{"Authorization": "JWT ${token}$"}', '123'))
99 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/test_mall.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | import sys
3 |
4 | sys.path.append('../')
5 | import pytest
6 | import requests
7 | from utils.RequestsUtil import Request, r_get,r_post
8 | from common.Base import init_db
9 |
10 | request = Request(url='http://211.103.136.242:8064')
11 |
12 | def test_login():
13 | """
14 | 登录
15 | """
16 | conn = init_db('db_1')
17 | res_db = conn.fetch_one('select id from tb_user where username="python"')
18 | print(f"数据库查询数据:{res_db}")
19 |
20 | url = 'http://211.103.136.242:8064/authorizations/'
21 | data = {'username':'python', 'password':'12345678'}
22 |
23 | r = r_post(url, json=data)
24 | print(r)
25 | '''
26 | {
27 | 'token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6Ijk1MjY3MzYzOEBxcS5jb20iLCJleHAiOjE1NzM1NzE3ODAsInVzZXJuYW1lIjoicHl0aG9uIiwidXNlcl9pZCI6MX0.CDnyS9thrPFk40Z7PX4vbBTJnzQT582xlsaFZbkRnMs',
28 | 'username': 'python',
29 | 'user_id': 1
30 | }
31 | '''
32 |
33 | def info():
34 | url = 'http://211.103.136.242:8064/user/'
35 | token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6Ijk1MjY3MzYzOEBxcS5jb20iLCJleHAiOjE1NzM1NzE3ODAsInVzZXJuYW1lIjoicHl0aG9uIiwidXNlcl9pZCI6MX0.CDnyS9thrPFk40Z7PX4vbBTJnzQT582xlsaFZbkRnMs'
36 | headers = {
37 | 'Authorization':'JWT ' + token
38 | }
39 |
40 | r = r_get(url, headers=headers)
41 |
42 | print(r)
43 |
44 | def goods_list():
45 | url = 'http://211.103.136.242:8064/categories/115/skus/'
46 | data = {
47 | 'page':"1",
48 | 'page_size':"10",
49 | 'ordering':"create_time"
50 | }
51 |
52 | r = r_get(url,json=data)
53 | print(r)
54 |
55 | def cart():
56 | url = 'http://211.103.136.242:8064/cart/'
57 | data = {
58 | 'sku_id':"3",
59 | 'count':"1",
60 | 'selected':True
61 | }
62 | token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6Ijk1MjY3MzYzOEBxcS5jb20iLCJleHAiOjE1NzM1NzE3ODAsInVzZXJuYW1lIjoicHl0aG9uIiwidXNlcl9pZCI6MX0.CDnyS9thrPFk40Z7PX4vbBTJnzQT582xlsaFZbkRnMs'
63 | headers = {
64 | 'Authorization':'JWT ' + token
65 | }
66 |
67 | r = r_post(url, json=data, headers=headers)
68 |
69 | print(r)
70 |
71 |
72 | def order():
73 | url = 'http://211.103.136.242:8064/orders/'
74 | data = {
75 | 'address':"1",
76 | 'pay_method':"1"
77 | }
78 | token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6Ijk1MjY3MzYzOEBxcS5jb20iLCJleHAiOjE1NzM1NzE3ODAsInVzZXJuYW1lIjoicHl0aG9uIiwidXNlcl9pZCI6MX0.CDnyS9thrPFk40Z7PX4vbBTJnzQT582xlsaFZbkRnMs'
79 | headers = {
80 | 'Authorization':'JWT ' + token
81 | }
82 | r = r_post(url, json=data, headers=headers)
83 |
84 | print(r)
85 |
86 | if __name__ == "__main__":
87 | # login()
88 | # info()
89 | # goods_list()
90 | # cart()
91 | # order()
92 | pytest.main(['-s'])
93 |
94 |
95 |
96 |
97 | """
98 | 1. 根据默认运行原则,调整py文件命名,函数命名
99 | 2. pytest.main()运行,或者命令行直接运行
100 | """
101 |
102 |
103 |
--------------------------------------------------------------------------------
/InterAutoTest_W/report/assets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Helvetica, Arial, sans-serif;
3 | font-size: 12px;
4 | /* do not increase min-width as some may use split screens */
5 | min-width: 800px;
6 | color: #999;
7 | }
8 |
9 | h1 {
10 | font-size: 24px;
11 | color: black;
12 | }
13 |
14 | h2 {
15 | font-size: 16px;
16 | color: black;
17 | }
18 |
19 | p {
20 | color: black;
21 | }
22 |
23 | a {
24 | color: #999;
25 | }
26 |
27 | table {
28 | border-collapse: collapse;
29 | }
30 |
31 | /******************************
32 | * SUMMARY INFORMATION
33 | ******************************/
34 |
35 | #environment td {
36 | padding: 5px;
37 | border: 1px solid #E6E6E6;
38 | }
39 |
40 | #environment tr:nth-child(odd) {
41 | background-color: #f6f6f6;
42 | }
43 |
44 | /******************************
45 | * TEST RESULT COLORS
46 | ******************************/
47 | span.passed, .passed .col-result {
48 | color: green;
49 | }
50 | span.skipped, span.xfailed, span.rerun, .skipped .col-result, .xfailed .col-result, .rerun .col-result {
51 | color: orange;
52 | }
53 | span.error, span.failed, span.xpassed, .error .col-result, .failed .col-result, .xpassed .col-result {
54 | color: red;
55 | }
56 |
57 |
58 | /******************************
59 | * RESULTS TABLE
60 | *
61 | * 1. Table Layout
62 | * 2. Extra
63 | * 3. Sorting items
64 | *
65 | ******************************/
66 |
67 | /*------------------
68 | * 1. Table Layout
69 | *------------------*/
70 |
71 | #results-table {
72 | border: 1px solid #e6e6e6;
73 | color: #999;
74 | font-size: 12px;
75 | width: 100%
76 | }
77 |
78 | #results-table th, #results-table td {
79 | padding: 5px;
80 | border: 1px solid #E6E6E6;
81 | text-align: left
82 | }
83 | #results-table th {
84 | font-weight: bold
85 | }
86 |
87 | /*------------------
88 | * 2. Extra
89 | *------------------*/
90 |
91 | .log:only-child {
92 | height: inherit
93 | }
94 | .log {
95 | background-color: #e6e6e6;
96 | border: 1px solid #e6e6e6;
97 | color: black;
98 | display: block;
99 | font-family: "Courier New", Courier, monospace;
100 | height: 230px;
101 | overflow-y: scroll;
102 | padding: 5px;
103 | white-space: pre-wrap
104 | }
105 | div.image {
106 | border: 1px solid #e6e6e6;
107 | float: right;
108 | height: 240px;
109 | margin-left: 5px;
110 | overflow: hidden;
111 | width: 320px
112 | }
113 | div.image img {
114 | width: 320px
115 | }
116 | .collapsed {
117 | display: none;
118 | }
119 | .expander::after {
120 | content: " (show details)";
121 | color: #BBB;
122 | font-style: italic;
123 | cursor: pointer;
124 | }
125 | .collapser::after {
126 | content: " (hide details)";
127 | color: #BBB;
128 | font-style: italic;
129 | cursor: pointer;
130 | }
131 |
132 | /*------------------
133 | * 3. Sorting items
134 | *------------------*/
135 | .sortable {
136 | cursor: pointer;
137 | }
138 |
139 | .sort-icon {
140 | font-size: 0px;
141 | float: left;
142 | margin-right: 5px;
143 | margin-top: 5px;
144 | /*triangle*/
145 | width: 0;
146 | height: 0;
147 | border-left: 8px solid transparent;
148 | border-right: 8px solid transparent;
149 | }
150 |
151 | .inactive .sort-icon {
152 | /*finish triangle*/
153 | border-top: 8px solid #E6E6E6;
154 | }
155 |
156 | .asc.active .sort-icon {
157 | /*finish triangle*/
158 | border-bottom: 8px solid #999;
159 | }
160 |
161 | .desc.active .sort-icon {
162 | /*finish triangle*/
163 | border-top: 8px solid #999;
164 | }
165 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/t_pytest/report/assets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Helvetica, Arial, sans-serif;
3 | font-size: 12px;
4 | /* do not increase min-width as some may use split screens */
5 | min-width: 800px;
6 | color: #999;
7 | }
8 |
9 | h1 {
10 | font-size: 24px;
11 | color: black;
12 | }
13 |
14 | h2 {
15 | font-size: 16px;
16 | color: black;
17 | }
18 |
19 | p {
20 | color: black;
21 | }
22 |
23 | a {
24 | color: #999;
25 | }
26 |
27 | table {
28 | border-collapse: collapse;
29 | }
30 |
31 | /******************************
32 | * SUMMARY INFORMATION
33 | ******************************/
34 |
35 | #environment td {
36 | padding: 5px;
37 | border: 1px solid #E6E6E6;
38 | }
39 |
40 | #environment tr:nth-child(odd) {
41 | background-color: #f6f6f6;
42 | }
43 |
44 | /******************************
45 | * TEST RESULT COLORS
46 | ******************************/
47 | span.passed, .passed .col-result {
48 | color: green;
49 | }
50 | span.skipped, span.xfailed, span.rerun, .skipped .col-result, .xfailed .col-result, .rerun .col-result {
51 | color: orange;
52 | }
53 | span.error, span.failed, span.xpassed, .error .col-result, .failed .col-result, .xpassed .col-result {
54 | color: red;
55 | }
56 |
57 |
58 | /******************************
59 | * RESULTS TABLE
60 | *
61 | * 1. Table Layout
62 | * 2. Extra
63 | * 3. Sorting items
64 | *
65 | ******************************/
66 |
67 | /*------------------
68 | * 1. Table Layout
69 | *------------------*/
70 |
71 | #results-table {
72 | border: 1px solid #e6e6e6;
73 | color: #999;
74 | font-size: 12px;
75 | width: 100%
76 | }
77 |
78 | #results-table th, #results-table td {
79 | padding: 5px;
80 | border: 1px solid #E6E6E6;
81 | text-align: left
82 | }
83 | #results-table th {
84 | font-weight: bold
85 | }
86 |
87 | /*------------------
88 | * 2. Extra
89 | *------------------*/
90 |
91 | .log:only-child {
92 | height: inherit
93 | }
94 | .log {
95 | background-color: #e6e6e6;
96 | border: 1px solid #e6e6e6;
97 | color: black;
98 | display: block;
99 | font-family: "Courier New", Courier, monospace;
100 | height: 230px;
101 | overflow-y: scroll;
102 | padding: 5px;
103 | white-space: pre-wrap
104 | }
105 | div.image {
106 | border: 1px solid #e6e6e6;
107 | float: right;
108 | height: 240px;
109 | margin-left: 5px;
110 | overflow: hidden;
111 | width: 320px
112 | }
113 | div.image img {
114 | width: 320px
115 | }
116 | .collapsed {
117 | display: none;
118 | }
119 | .expander::after {
120 | content: " (show details)";
121 | color: #BBB;
122 | font-style: italic;
123 | cursor: pointer;
124 | }
125 | .collapser::after {
126 | content: " (hide details)";
127 | color: #BBB;
128 | font-style: italic;
129 | cursor: pointer;
130 | }
131 |
132 | /*------------------
133 | * 3. Sorting items
134 | *------------------*/
135 | .sortable {
136 | cursor: pointer;
137 | }
138 |
139 | .sort-icon {
140 | font-size: 0px;
141 | float: left;
142 | margin-right: 5px;
143 | margin-top: 5px;
144 | /*triangle*/
145 | width: 0;
146 | height: 0;
147 | border-left: 8px solid transparent;
148 | border-right: 8px solid transparent;
149 | }
150 |
151 | .inactive .sort-icon {
152 | /*finish triangle*/
153 | border-top: 8px solid #E6E6E6;
154 | }
155 |
156 | .asc.active .sort-icon {
157 | /*finish triangle*/
158 | border-bottom: 8px solid #999;
159 | }
160 |
161 | .desc.active .sort-icon {
162 | /*finish triangle*/
163 | border-top: 8px solid #999;
164 | }
165 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/test_excel_case.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 | # 1. 初始化信息
4 | # 1) 初始化测试用例文件
5 | # 2) 测试用例sheet名称
6 | # 3) 获取运行测试用例列表
7 | # 4) 日志
8 | # 2. 测试用例方法,参数化运行
9 |
10 | import os
11 | import sys
12 | sys.path.append('../')
13 | import pytest
14 | import json
15 | import re
16 | import allure
17 |
18 | from config import Conf
19 | from config.Conf import ConfigYaml
20 | from common.ExcelData import Data
21 | from utils.LogUtil import my_log
22 | from common import ExcelConfig
23 | from common import Base
24 | from utils.RequestsUtil import Request
25 | from utils.AssertUtil import AssertUtil
26 |
27 | case_file = os.path.join(Conf.get_data_path, ConfigYaml().get_excel_file())
28 | sheet_name = ConfigYaml().get_excel_sheet()
29 | data_init = Data(case_file, sheet_name)
30 | run_list = data_init.get_run_data()
31 |
32 | log = my_log()
33 |
34 | # 初始化dataconfig
35 | data_key = ExcelConfig.DataConfig
36 |
37 | # 一个用例运行
38 | # 1)初始化信息, url, data
39 | # 2) 接口请求
40 | class TestExcel():
41 | # 1. 增加pytest
42 | # 2. 修改方法参数
43 | # 3. 重构函数内容
44 | # 4. pytest.main
45 |
46 | def run_pre(self, pre_case):
47 | url = pre_case[data_key.url]
48 | method = pre_case[data_key.method]
49 | params = pre_case[data_key.params]
50 | headers = pre_case[data_key.headers]
51 | cookies = pre_case[data_key.cookies]
52 |
53 | # 增加headers
54 | header = Base.json_parse(headers)
55 | # 增加cookies
56 | cookie = Base.json_parse(cookies)
57 | res = self.run_api(url, params, method, header, cookie)
58 | print(f"执行前置用例: {res}")
59 | return res
60 |
61 |
62 | def run_api(self,url, params, method ='get', header=None, cookie=None):
63 | """
64 | 发送请求
65 | """
66 | request = Request(ConfigYaml().get_config_url())
67 | if not len(str(params).strip()):
68 | return params
69 | params = json.loads(params)
70 | if str(method).lower() == "get":
71 | res = request.get(url,json=params,headers=header,cookies=cookie)
72 | log.debug('get请求')
73 | elif str(method).lower() == "post":
74 | res = request.post(url, json=params,headers=header,cookies=cookie)
75 | log.debug('post请求')
76 | else:
77 | log.error(f"错误的请求方法:{method}")
78 | return res
79 |
80 |
81 | @pytest.mark.parametrize('case', run_list)
82 | def test_run(self,case):
83 | # data_key = ExcelConfig.DataConfig
84 | url = case[data_key.url]
85 | case_id = case[data_key.case_id]
86 | case_model = case[data_key.case_model]
87 | case_name = case[data_key.case_name]
88 | pre_exec = case[data_key.pre_exec]
89 | method = case[data_key.method]
90 | params_type = case[data_key.params_type]
91 | params = case[data_key.params]
92 | expect_result = case[data_key.expect_result]
93 | actual_result = case[data_key.actual_result]
94 | beizhu = case[data_key.beizhu]
95 | headers = case[data_key.headers]
96 | cookies = case[data_key.cookies]
97 | code = case[data_key.code]
98 | db_verify = case[data_key.db_verify]
99 |
100 | if pre_exec:
101 | # 前置用例
102 | pre_case = data_init.get_case_pre(pre_exec)
103 | # print(f"前置条件信息为:{pre_case}")
104 | pre_res = self.run_pre(pre_case)
105 | headers, cookies = self.get_correlation(headers, cookies,pre_res)
106 |
107 | # 增加headers
108 | header = Base.json_parse(headers)
109 | # 增加cookies
110 | cookie = Base.json_parse(cookies)
111 | request = Request(ConfigYaml().get_config_url())
112 | # params转义json
113 | # 验证params有没有内容
114 | res = self.run_api(url, params, method, header, cookie)
115 | print(f"执行测试用例:{res}")
116 |
117 | # allure
118 | allure.dynamic.feature(sheet_name)
119 | allure.dynamic.story(case_model)
120 | allure.dynamic.title(case_id + case_name)
121 | desc = f"url:{url}
请求方法:{method}
期望结果:{expect_result}
实际结果:{res}"
122 | allure.dynamic.description(desc)
123 |
124 |
125 | # 断言验证
126 | assert_util = AssertUtil()
127 | assert_util.assert_code(int(res['code']), code)
128 | assert_util.assert_in_body(str(res['body']), str(expect_result))
129 |
130 |
131 | # 数据库验证
132 | # sql = Base.init_db('db_1')
133 | # db_res = sql.fetch_one(db_verify)
134 | # log.debug(f"数据库查询结果:{str(db_res)}")
135 | # for db_k,db_v in db_res.items():
136 | # res_line = res['body'][db_k]
137 | # assert_util.assert_body(res_line, db_v)
138 | Base.assert_db(db_name ='db_1', res_body=res['body'], db_verify=db_verify )
139 |
140 | def get_correlation(self, headers, cookies, pre_res):
141 | """
142 | 关联
143 | """
144 | # 验证是否有关联
145 | headers_para, cookies_para= Base.params_find(headers, cookies)
146 | # 有关联执行前置用例,获取结果
147 | if len(headers_para):
148 | headers_data = pre_res['body'][headers_para[0]]
149 | # 结果替换
150 | headers = Base.res_sub(headers, headers_data)
151 |
152 | if len(cookies_para):
153 | cookies_data = pre_res['body'][cookies_para[0]]
154 | # 结果替换
155 | cookies = Base.res_sub(headers, cookies_data)
156 |
157 | return headers, cookies
158 |
159 | if __name__ == "__main__":
160 | report_path = Conf._report_path()
161 | pytest.main(['-s', 'test_excel_case.py', '--alluredir', report_path+'/reslut'])
162 | Base.allure_report(report_path)
163 | # TestExcel().test_run()
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
--------------------------------------------------------------------------------
/InterAutoTest_W/testcase/t_pytest/report/report.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Report generated on 26-Nov-2019 at 18:15:56 by pytest-html v2.0.1
245 || JAVA_HOME | 249 |C:\Develop\java\JDK |
| Packages | 252 |{'pytest': '5.3.0', 'py': '1.8.0', 'pluggy': '0.13.1'} |
| Platform | 255 |Windows-10-10.0.18362-SP0 |
| Plugins | 258 |{'arraydiff': '0.3', 'doctestplus': '0.3.0', 'html': '2.0.1', 'metadata': '1.8.0', 'openfiles': '0.3.2', 'remotedata': '0.3.1', 'rerunfailures': '8.0'} |
| Python | 261 |3.7.3 |
2 tests ran in 0.05 seconds.
264 |(Un)check the boxes to filter the results.
2 passed, 0 skipped, 0 failed, 0 errors, 0 expected failures, 0 unexpected passes, 0 rerun 265 || Result | 270 |Test | 271 |Duration | 272 |Links |
|---|---|---|---|
| No results found. Try to check the filters | |||
| Passed | 278 |testcase/t_pytest/pytest_more.py::TestClass::test_a[xiaoming-12345] | 279 |0.00 | 280 ||
|
283 | No log output captured. | |||
| Passed | 287 |testcase/t_pytest/pytest_more.py::TestClass::test_a[xiaohong-56789] | 288 |0.00 | 289 ||
|
292 | No log output captured. | |||
Report generated on 28-Nov-2019 at 00:04:49 by pytest-html v2.0.1
245 || JAVA_HOME | 249 |C:\Develop\java\JDK |
| Packages | 252 |{'pytest': '5.3.1', 'py': '1.8.0', 'pluggy': '0.13.1'} |
| Platform | 255 |Windows-10-10.0.18362-SP0 |
| Plugins | 258 |{'html': '2.0.1', 'metadata': '1.8.0', 'rerunfailures': '8.0'} |
| Python | 261 |3.8.0 |
0 tests ran in 0.61 seconds.
264 |(Un)check the boxes to filter the results.
0 passed, 0 skipped, 0 failed, 2 errors, 0 expected failures, 0 unexpected passes, 0 rerun 265 || Result | 270 |Test | 271 |Duration | 272 |Links |
|---|---|---|---|
| No results found. Try to check the filters | |||
| Error | 278 |testcase/test_excel_case.py::collect | 279 |0.00 | 280 ||
|
283 | testcase\test_excel_case.py:24: in <module> run_list = Data(case_file, sheet_name).get_run_data() common\ExcelData.py:13: in __init__ self.reader = ExcelReader(excel_file, sheet_by) utils\ExcelUtil.py:27: in __init__ raise FileNotFoundError("文件不存在") E FileNotFoundError: 文件不存在 | |||
| Error | 287 |testcase/test_mall.py::collect | 288 |0.00 | 289 ||
|
292 | ImportError while importing test module 'E:\学习\测试\InterAutoTest_W\testcase\test_mall.py'. Hint: make sure your test modules/packages have valid Python names. Traceback: testcase\test_mall.py:8: in <module> from common.Base import init_db common\Base.py:7: in <module> from utils.MysqlUtil import Mysql utils\MysqlUtil.py:11: in <module> from utils.LogUItil import my_log E ModuleNotFoundError: No module named 'utils.LogUItil' | |||