2 |
3 | |
4 |
9 | |
10 |
11 |
12 |
13 |
14 |
15 | | Hello All: |
16 |
17 |
18 | |
19 | 本次为考勤系统项目接口测试邮件,已经测试完毕(附件为本次测试报告)
20 | |
21 |
22 |
23 | |
24 | 如有问题,及时反馈!谢谢!
25 | |
26 |
27 |
28 | | 注意事项: |
29 |
30 |
31 | |
32 | 1. 邮件为每日定点发送, 如有打扰抱歉!
33 | |
34 |
35 |
36 | |
37 | 2. 如发现存在失败的用例,请及时检查!
38 | |
39 |
40 |
41 | |
42 | 3. 运行用例皆为框架自动生成, 如有纰漏及时检查。
43 | |
44 |
45 |
46 | |
47 | 4. 测试框架在不断升级ing, 如有使用上的问题请及时联系Null.
48 | |
49 |
50 |
51 | |
52 |
53 |
54 |
55 |
56 |
57 | | 结果数据统计如下: |
58 |
59 |
60 | |
61 |
62 |
63 |
64 |
65 |
66 | | 序号 |
67 | 用例名称 |
68 | 用例总数 |
69 | 用例通过 |
70 | 用例失败 |
71 | 用例跳过 |
72 |
73 |
74 | | 1 |
75 | Report |
76 | 5 |
77 | 2 |
78 | 3 |
79 | 0 |
80 |
81 |
82 | |
83 |
84 |
85 |
86 |
87 |
88 |
89 | | Id |
90 | TestSuite |
91 | TestCase |
92 | Description |
93 | Url |
94 | Method |
95 |
96 |
97 |
98 | | 1 |
99 | Apilogin |
100 | test_api_login_success |
101 | 登录成功-/v31/mem/action/login |
102 | /v31/mem/action/login |
103 | post |
104 |
105 |
106 |
107 | | 2 |
108 | Apilogin |
109 | test_login_fail |
110 | 登录失败-/v31/mem/action/login |
111 | /v31/mem/action/login |
112 | post |
113 |
114 |
115 |
116 | | 3 |
117 | Coupon |
118 | test_coupon_success |
119 | 优惠券-/v40/disCoupon/own |
120 | /v40/disCoupon/own |
121 | get |
122 |
123 |
124 |
125 | |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 | |
134 | 如有任何问题或需要帮助,欢迎随时与我联系。
135 | |
136 |
137 |
138 | |
139 | 联系人:Null
140 | |
141 |
142 |
143 | |
144 | QQ:546464268
145 | |
146 |
147 |
148 |
149 | |
150 |
151 |
152 | |
153 | Copyright© MeteorTearsTeam
154 | |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/lib/public/load_cases.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import yaml
3 | from os import path
4 | from lib.utils import fp
5 | from lib.public import logger
6 | from lib.utils import exceptions
7 | from config import setting
8 | from collections import Iterable
9 | from lib.public.Recursion import GetJsonParams
10 | from lib.public import relevance
11 |
12 |
13 | TestMap = {
14 | "api": [],
15 | "cases": [],
16 | 'PWD': setting.BASE_DIR
17 | }
18 |
19 | ExtendCaseMap = {}
20 |
21 | get_value = lambda seq, key: GetJsonParams.get_value(seq, key)
22 |
23 |
24 | class LoadCase(object):
25 |
26 | def __init__(self, path: str = None):
27 | self.path = path
28 |
29 | def get_all_files(self) -> list:
30 | r"""返回文件目录路径下全部文件列表
31 |
32 | :Usage:
33 | get_all_files()
34 | """
35 | return fp.iter_files(self.path)
36 |
37 | @property
38 | def __get_files_name(self) -> list:
39 | r"""返回文件目录下的文件名
40 |
41 | :Usage:
42 | __get_files_name
43 | """
44 | return fp.iter_files(self.path, otype='name')
45 |
46 | @staticmethod
47 | def load_yaml_file(filepath) -> dict:
48 | r"""加载并读取.yaml格式文件
49 |
50 | :Args:
51 | - filepath: yaml文件路径, str object.
52 | """
53 | with open(filepath, encoding='utf-8') as stream:
54 | file_content = yaml.safe_load(stream)
55 | return file_content
56 |
57 | def load_file(self, file_path: str) -> dict:
58 | r"""加载单个.yaml测试用例文件
59 |
60 | :Args:
61 | - file_path: yaml文件路径, str object.
62 | """
63 | if not path.isfile(file_path):
64 | raise exceptions.CaseYamlFileNotFound("{} does not exist.".format(file_path))
65 |
66 | file_suffix = path.splitext(file_path)[1].lower()
67 | if file_suffix in ['.yaml', '.yml']:
68 | return self.load_yaml_file(file_path)
69 | else:
70 | err_msg = u"Unsupported file format: {}".format(file_path)
71 | logger.log_error(err_msg)
72 | return {}
73 |
74 | def load_files(self) -> list:
75 | r"""加载cases目录下的用例文件
76 |
77 | :Usage:
78 | load_files()
79 | """
80 | files_list = []
81 | for index, file in enumerate(self.get_all_files()):
82 | class_name = self.__get_files_name[index].split('.')[0].title().replace('_', '')
83 | try:
84 | with open(file, encoding='utf-8') as f:
85 | files_list.append({class_name: yaml.safe_load(f)})
86 | except exceptions.JsonLoadingError as err:
87 | logger.log_error(
88 | "Json file parsing error, error file: {0}, error message: {1}".format(
89 | file, err))
90 | return files_list
91 |
92 | def classification_cases(self) -> tuple:
93 | r"""加载cases文件夹下的用例数据,并对数据进行分类
94 | """
95 |
96 | for yaml_content in self.load_files():
97 | _extend_cases_path = get_value(yaml_content, 'testcases')
98 | _extend_api_path = get_value(yaml_content, 'apipath')
99 |
100 | # if _extend_cases_path:
101 | # TestMap['suites'].append(yaml_content)
102 | # testcase_path = path.join(
103 | # TestMap['PWD'],
104 | # *_extend_cases_path.split('/')
105 | # )
106 | # test_dict = self.load_file(testcase_path)
107 | # ExtendCaseMap[_extend_cases_path] = test_dict
108 |
109 | if _extend_api_path:
110 | TestMap['cases'].append(yaml_content)
111 | testapi_path = path.join(
112 | TestMap['PWD'],
113 | *_extend_api_path.split('/')
114 | )
115 | test_dict = self.load_file(testapi_path)
116 | ExtendCaseMap[_extend_api_path] = test_dict
117 | if not _extend_cases_path and not _extend_api_path:
118 | TestMap['api'].append(yaml_content)
119 |
120 | return TestMap, ExtendCaseMap
121 |
122 | def _case_loads_inherit_case(self) -> tuple:
123 | r"""对于测试用例中调用或有继承关系的yaml文件,将testapi字段的文件路径替换成具体的用例数据.
124 | """
125 | cases = {}
126 | cases_set, extend_cases = self.classification_cases()
127 | for tags in cases_set['cases']:
128 |
129 | for class_name, content in tags.items():
130 | for case_name, value in content.items():
131 | extend_case_flag = get_value(tags, 'extend_api')
132 | if extend_case_flag:
133 |
134 | _relevance = {}
135 | for extend_case in extend_case_flag:
136 | extend_case_path = setting.API_PATH + extend_case + '.yaml'
137 | with open(extend_case_path, encoding='utf-8') as file:
138 | _relevance.update(yaml.safe_load(file))
139 | relevance_body = relevance.custom_manage(str(value), _relevance, '2')
140 | cases.update({class_name: {case_name: relevance_body}})
141 | return cases, extend_cases
142 | # return cases, extend_cases
143 | # inks, ouks, sub_key, sub_dict = [], [], [], {}
144 | # for case in dict(cases_set)['cases']:
145 | # if isinstance(case, Iterable):
146 | # for keys in dict(case).keys():
147 | # ouks.append(keys)+++
148 | # for cases_keys in dict(case)[keys]:
149 | # inks.append(cases_keys)
150 | #
151 | # for ink in inks:
152 | # sub_key.append(dict(GetJsonParams.get_value(cases_set, ink))['testapi'])
153 | #
154 | # for key, value in dict(extend_cases).items():
155 | # if key in sub_key:
156 | # sub_dict.update(value)
157 | #
158 | # try:
159 | # for sui_index in range(len(cases_set['cases'])):
160 | # for index, ink in enumerate(inks):
161 | # cases_set['cases'][sui_index][ouks[index]][ink]['testapi'] = sub_dict
162 | # except (KeyError, ValueError):
163 | # pass
164 |
165 | # return cases_set, extend_cases
166 |
167 | def sub_case_func_params(self):
168 | r""" 将继承case中需要入参的参数替换params_keys中的各个值
169 | 入参:
170 | params_kwargs:
171 | - username: tracy.liu
172 | - password: 12345678
173 | 传参:
174 | func_params: [username, password]
175 | json:
176 | ${username}$
177 | ${password}$
178 | """
179 | ncases = {
180 | 'cases': [
181 | ]
182 | }
183 | api_case_set, extend_cases = self._case_loads_inherit_case()
184 | func_params = GetJsonParams.get_value(extend_cases, 'func_params')
185 | params_kwargs = GetJsonParams.get_value(api_case_set['cases'], 'params_kwargs')
186 | if isinstance(func_params, Iterable) and isinstance(params_kwargs, Iterable):
187 |
188 | for case in api_case_set['cases']:
189 | _relevance = {}
190 | for func_param in func_params:
191 | _relevance.update({func_param: dict(params_kwargs)[func_param]})
192 |
193 | relevance_body = relevance.custom_manage(str(case), _relevance, '1')
194 | ncases['cases'].append(relevance_body)
195 |
196 | return ncases['cases']
197 |
198 |
199 | class Containers(object):
200 |
201 | def __init__(self, crop: dict):
202 | self.crop = crop
203 |
204 | def __repr__(self):
205 | return "Containers <{}->{}>".format(
206 | self.crop.get('class_name'),
207 | self.crop.get('func_name')
208 | )
209 |
--------------------------------------------------------------------------------
/update_log.md:
--------------------------------------------------------------------------------
1 | ### 2019-06-28
2 | 1. 对测试用例数据执行前进行预处理
3 | ```示例
4 | 测试用例分层结构:
5 | 1.其中testapi目录不会执行
6 | 2.api文件和csase文件调用
7 | a.testapi
8 | 以$