class Wework(BaseApi): """ 获取企业微信的access_token,后续应该得写在BaseApi的父类,这个类没啥必要了 CORP_ID:企业微信的企业id """ # 通过配置文件获取企业微信的id CORP_ID = cf.get_key("wwork", "corp_id") def get_token(self, secret): """ 获取access_token,不同的应用的秘钥,会产生不同的access_token,所以就封装起来了 :param secret: 企业微信不同也应用的密码 :return: access_token的值 """ data = { "method": "GET", "url": f"https://qyapi.weixin.qq.com/cgi-bin/gettoken", "params": f"corpid={self.CORP_ID}&corpsecret={secret}" } # 使用send_api,传入data,相当于使用了requests了 res = self.send_api(data) # 获取access_token token = res["access_token"] return token
class Department(BaseApi): base_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) ip = cf.get_key("env", "formal_ip") def get_depart(self, id=None): p_data = {"ip": self.ip, "token": token, "id": id} res = self.send_api_data("data/department/department_api.yml", p_data, "get") return res
class Wework(BaseApi): # 通过配置文件获取企业微信的id corpid = cf.get_key("wwork", "corp_id") # 获取access_token,不同的应用的秘钥,会产生不同的access_token,所以就封装起来了 def get_token(self, secret): data = { "method": "GET", "url": f"https://qyapi.weixin.qq.com/cgi-bin/gettoken?", "params": f"corpid={self.corpid}&corpsecret={secret}" } # 使用send_api,传入data,相当于使用了requests了 res = self.send_api(data) # 获取access_token token = res["access_token"] return token
def set_file(self): # 日期:创造Log_2020-12-03.log文件 a = self.log_name+"_"+str(datetime.date.today()) + ".logs" b = os.path.join(self.BASE_PATH,"logs",a) # 通过配置文件,获取log是w模式还是a的追加模式 file_mode=cf.get_key("logs","file_mode") # 文件处理器,文件名为demo.logs filehandle = logging.FileHandler(filename=b,mode=file_mode) # 默认等级为INFO filehandle.setLevel(logging.INFO) # 处理器添加格式,这里都添加同一个 filehandle.setFormatter(self.formatter) # 记录器添加处理器,就拥有了屏幕输出的和文件输出的日志了 self.logger.addHandler(filehandle)
def __init__(self): """ 初始化mysql的conn对家,连接数据库 """ # 通过配置文件获取数据库的host,port,username,password,charset,database host = cf.get_key("mysql", "host") # 从配置文件获取的值是str,需要转化成int port = int(cf.get_key("mysql", "port")) user = cf.get_key("mysql", "user") password = cf.get_key("mysql", "password") charset = cf.get_key("mysql", "charset") database = cf.get_key("mysql", "database") # 当无法连接数据库,走异常处理处理 try: self.conn = pymysql.connect(host=host, port=port, user=user, password=password, charset=charset, database=database) except Exception as e: log.error(f"无法登陆数据库,错误原因:{e}")
class WCalendar(BaseApi): """ 企业微信日程中的日历模块的API类 secret:日历的秘钥 token:日历的token yml_api_path: yml api数据的相对路径 """ # 通过配置文件获取日历的secret,token只是为了测试方法,其实不应该存在的 secret = cf.get_key("wwork", "schedule_secret") token = Wework().get_token(secret) # yml api数据的相对路径 yml_api_path = "data/schedule/calendar/calendar_api.yml" # 不用yml文件保存cal_id的数据了,放在数据库好啦 # cal_id_path="data/schedule/calendar/cal_id.yml" def get_cal_id_list(self): """ 通过数据库,获取日历id的值,日历id的值无法通过接口获取,所以就保存在数据库中 :return: 返回全部的日历id的列表 """ # 执行sql语句获取日历id的元祖 cal_id_tuple = sql.select("select cal_id from cal_id") # 把元祖转化成列表 cal_id_list = [i[0] for i in cal_id_tuple] return cal_id_list def add_calendar(self, token, organizer, readonly, set_as_default, summary, color, description): """ 添加日历 :param token: access_token的值 :param organizer: 请求参数的值 :param readonly: 请求参数的值 :param set_as_default: 请求参数的值 :param summary: 请求参数的值 :param color: 请求参数的值 :param description: 请求参数的值 :return: 返回响应体 """ # Template模板需要二次改变的值 p_data = {"ip": self.ip, "token": token, "organizer": organizer, "readonly": readonly, "set_as_default": set_as_default, "summary": summary, "color": color, "description": description} res = self.send_api_data(self.yml_api_path, p_data, "add") try: cal_id = res["cal_id"] # 当cal_id获取到了,就把cal_id放到数据库中 sql.insert(f"insert into cal_id(userid,cal_id) values('{organizer}','{cal_id}')") except KeyError: log.error(f"响应不正确,无法插入数据") # 用yml文件保存数据的方法不要了 # try: # cal_id=res["cal_id"] # cal_id_list=self.load_yaml(self.cal_id_path) # cal_id_list.append(cal_id) # cal_id_list=list(filter(None,cal_id_list)) # self.save_yaml(self.cal_id_path,cal_id_list) # except: # log.info(f"无法获取到cal_id") return res def get_calendar(self, token, index=None): """ 获取日历信息 :param token: 日历的token值 :param index: 在数据库获取第几个id值 :return: 返回响应体 """ # 解决index存在的时候,传的cal_id_list是一个列表 cal_id_list = [] # 从数据库获取cal_id_list,才能查询日历 if index is None: cal_id_list = self.get_cal_id_list() else: cal_id_list.append(self.get_cal_id_list()[index]) p_data = {"ip": self.ip, "token": token, "cal_id_list": cal_id_list} res = self.send_api_data(self.yml_api_path, p_data, "get") return res def delete_calendar(self, token, index): """ 删除日历 :param token: 日历的token值 :param index: 在数据库获取第几个id值 :return: 返回响应体 """ # 从数据库获取cal_id_list cal_id = self.get_cal_id_list()[index] p_data = {"ip": self.ip, "token": token, "cal_id": cal_id} res = self.send_api_data(self.yml_api_path, p_data, "delete") # 当删除api成功时,同步从数据库中删除cal_id if res["errcode"] == 0: sql.delete(f"delete from cal_id where cal_id='{cal_id}'") else: log.info("日历删除请求有误,数据库没有删除cal_id") return res def edit_calendar(self, token, index, readonly, summary, color, description): """ 编辑日历 :param token: 日历的token值 :param index: 请求参数的值 :param readonly: 请求参数的值 :param summary: 请求参数的值 :param color: 请求参数的值 :param description: 请求参数的值 :return: 返回响应体 """ # 从数据库获取cal_id_list cal_id = self.get_cal_id_list()[index] p_data = {"ip": self.ip, "token": token, "cal_id": cal_id, "readonly": readonly, "summary": summary, "color": color, "description": description} res = self.send_api_data(self.yml_api_path, p_data, "edit") return res
class TestMember(): """ 联系人的测试类 1.参数化存放在特定的yml文件中,用三级目录管理用例、参数数据和ids的数据 2.token值并没有使用conftest的fixture,而是在测试类中获取,效率不高 3.并未对token的值做参数化 4.critical的用例等级为完整测试,blocker等级为冒烟测试 5.每个用例都配合fixture,完成了不同的前置和后置,实现了不同用例互不干扰的状态 """ @classmethod def get_token(cls, token): return token # 通过配置文件获取联系人的secret contact_secret = cf.get_key("wwork", "contact_secret") # 获取access_token token = Wework().get_token(contact_secret) # 初始化member的api对象 member = Member() # # 比如在类中,怎么才能导入这个conftest的token # access_token=token ''' 这样获取数据的方法,要读取两次文件,速度太慢了 add_data = member.load_yaml("data/member/member_para_data.yml")['add']['data'] add_ids = member.load_yaml("data/member/member_para_data.yml")['add']['ids'] ''' # 参数化的数据 para_data = member.load_yaml("data/member/member_para_data.yml") # 删除用例的参数化数据和ids标题数据 delete_data = para_data['delete']['data'] delete_ids = para_data['delete']['ids'] # 删除用例的参数化数据和ids标题数据 multi_delete_data = para_data['multi_delete']['data'] multi_delete_ids = para_data['multi_delete']['ids'] # 删除用例的参数化数据和ids标题数据 add_data = para_data['add']['data'] add_ids = para_data['add']['ids'] # 删除用例的参数化数据和ids标题数据 edit_data = para_data['edit']['data'] edit_ids = para_data['edit']['ids'] # 删除用例的参数化数据和ids标题数据 get_data = para_data['get']['data'] get_ids = para_data['get']['ids'] # 删除用例的参数化数据和ids标题数据 active_data = para_data['active']['data'] active_ids = para_data['active']['ids'] # 删除用例的参数化数据和ids标题数据 qr_data = para_data['qr']['data'] qr_ids = para_data['qr']['ids'] # 删除用例的参数化数据和ids标题数据 depart_simple_data = para_data['depart_simple']['data'] depart_simple_ids = para_data['depart_simple']['ids'] # 删除用例的参数化数据和ids标题数据 depart_explicit_data = para_data['depart_explicit']['data'] depart_explicit_ids = para_data['depart_explicit']['ids'] @allure.severity(allure.severity_level.CRITICAL) @allure.story("增加联系人") @pytest.mark.parametrize(("userid,name,mobile,errcode,errmsg"), add_data, ids=add_ids) def test01_add_member(self, userid, name, mobile, errcode, errmsg, add): log.info(f"-------开始测试增加成员-------") res = self.member.add_member(self.token, userid, name, mobile) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.CRITICAL) @allure.story("获得联系人信息") @pytest.mark.parametrize(("userid,errcode,errmsg"), get_data, ids=get_ids) def test02_get_member(self, userid, errcode, errmsg, get): log.info("-------开始测试获取成员-------") res = self.member.get_member_info(self.token, userid) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.CRITICAL) @allure.story("删除联系人") @pytest.mark.parametrize(("userid,errcode,errmsg"), delete_data, ids=delete_ids) def test04_delete_member(self, userid, errcode, errmsg, delete): log.info("-------开始测试获取成员-------") res = self.member.delete_member(self.token, userid) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.CRITICAL) @allure.story("批量删除联系人") @pytest.mark.parametrize(("userid_list,errcode,errmsg"), multi_delete_data, ids=multi_delete_ids) def test05_multi_delete_member(self, userid_list, errcode, errmsg, multi_delete): log.info("-------开始批量删除获取成员-------") res = self.member.multi_delete_member(self.token, userid_list) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.CRITICAL) @allure.story("编辑联系人") @pytest.mark.parametrize(("userid,name,mobile,errcode,errmsg"), edit_data, ids=edit_ids) def test03_edit_member(self, userid, name, mobile, errcode, errmsg, edit): log.info("-------开始修改获取成员-------") res = self.member.edit_member(self.token, userid, name, mobile) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.NORMAL) @allure.story("查看企业微信活跃度") @pytest.mark.parametrize(("date,errcode,errmsg"), active_data, ids=active_ids) def test_active_stat(self, date, errcode, errmsg): log.info("-------开始查看企业微信活跃度-------") res = self.member.get_active_stat(self.token, date) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.NORMAL) @allure.story("增加联系人") @pytest.mark.parametrize(("size,errcode,errmsg"), qr_data, ids=qr_ids) def test_get_invite_qr(self, size, errcode, errmsg): log.info("-------开始获取企业微信二维码-------") res = self.member.get_invite_qr(self.token, size) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.CRITICAL) @allure.story("查看部门联系人的简单信息") @pytest.mark.parametrize(("department_id,fetch_child,errcode,errmsg"), depart_simple_data, ids=depart_simple_ids) def test_get_depart_member(self, department_id, fetch_child, errcode, errmsg): log.info("-------开始获取部门成员简单的信息-------") res = self.member.get_depart_member(self.token, department_id, fetch_child) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.CRITICAL) @allure.story("查看部门联系人的复杂信息") @pytest.mark.parametrize(("department_id,fetch_child,errcode,errmsg"), depart_explicit_data, ids=depart_explicit_ids) def test_get_depart_member_explict(self, department_id, fetch_child, errcode, errmsg): log.info("-------开始部门成员详细信息-------") res = self.member.get_depart_member_explicit(self.token, department_id, fetch_child) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.BLOCKER) @allure.story("增加联系人") @pytest.mark.smoke def test_all_smoke_member(self, test_all_pre_data): add_res = self.member.add_member(self.token, "tong1234", "tong1234", "13172771165") edit_res = self.member.edit_member(self.token, "tong1234", "tong1234", "13172771165") del_res = self.member.delete_member(self.token, "tong1234") multi_del_res = self.member.multi_delete_member( self.token, ["tongtong1", "tongtong2", "tongtong3"]) qr_res = self.member.get_invite_qr(self.token, 1) active_res = self.member.get_active_stat(self.token, "2020-10-10") depart_res = self.member.get_depart_member(self.token, "1", "1") depart_res_e = self.member.get_depart_member_explicit( self.token, "1", "1") assert add_res["errcode"] == 0 assert edit_res["errcode"] == 0 assert del_res["errcode"] == 0 assert multi_del_res["errcode"] == 0 assert qr_res["errcode"] == 0 assert active_res["errcode"] == 40058 assert depart_res["errcode"] == 0 assert depart_res_e["errcode"] == 0 log.info("finish")
import os from api.base_api import BaseApi from api.wework import Wework from common.config import cf from common.get_log import log secret = cf.get_key("wwork", "contact_secret") token = Wework().get_token(secret) class Department(BaseApi): base_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) ip = cf.get_key("env", "formal_ip") def get_depart(self, id=None): p_data = {"ip": self.ip, "token": token, "id": id} res = self.send_api_data("data/department/department_api.yml", p_data, "get") return res if __name__ == "__main__": a = Department() print(a.get_depart())
class BaseApi: """ 实现了所有公共类API的需要的东西,是其他API的父类 ip:测试环境的ip地址 Base_Path:项目的根路径 """ # 通过配置文件获取测试的环境的ip地址 ip = cf.get_key("env", "formal_ip") Base_Path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) def send_api(self, req: dict): """ 封装requests代码,替代requests.request方法 :param req: 传入请求的字典数据,包括method,url,params,json :return: 响应体 """ """ req传入的数据类型如下 req={ "method":"GET", "url":f"https://qyapi.weixin.qq.com/cgi-bin/gettoken?", "params":f"corpid={self.corpid}&corpsecret={secret}" } request的参数接收method,url,params,data,json 把这些参数都写在一个字典里面,**req就可以解包 变成method="get",url="http://xxx",符合request传参的需求 """ res = requests.request(**req).json() return res @classmethod def get_time(cls, date): """ 时间字符串转化成时间戳,格式:2013-10-10 23:40:00,转化成1605021256的时间戳 :param date: 2013-10-10 23:40:00的时间格式 :return: 返回时间戳1605021256 """ # 先转换成时间格式对象,再转化成时间戳 time_strp = time.strptime(date, "%Y-%m-%d %H:%M:%S") time_stamp = int(time.mktime(time_strp)) return time_stamp @classmethod def jsonpath(cls, json, expr): """ 优化jsonpath代码,其他类就不用from jsonpath improt jsonpath了 :param json: 传入json格式,发现json或者字典都ok也 :param expr: 要获取json内容的表达式 :return: 返回想要的字符串 """ return jsonpath(json, expr) @classmethod def load_yaml(cls, path, sub=None): """ 封装yaml读取的代码,通过路径直接读取yml文件并转化成python数据类型 :param path: yml文件的相对路径 :param sub: 读取yml文件的二级数据目录,默认为None :return: 返回yml文件的python数据 """ # 链接根路径和yml文件的相对路径,简化文件路径 path = os.path.join(cls.Base_Path, path) with open(path, encoding="utf-8") as f: # 不写sub就获取yml的所有内容,写就获取yml的二级数据目录 if sub is None: return yaml.safe_load(f) else: return yaml.safe_load(f)[sub] @classmethod def save_yaml(cls, path, data): """ 封装yaml写入的代码 :param path: yml文件的相对路径 :param data: python的数据 """ # 链接根路径和yml文件的相对路径,简化文件路径 path = os.path.join(cls.Base_Path, path) with open( path, "r+", encoding="utf-8", ) as f: yaml.safe_dump(data, f) @classmethod def template(cls, path, data, sub=None): """ 使用模板技术,把yml文件中的变量进行二次转化,是本框架的yml文件的技术基础 :param path: 模板技术输入yml文件相对路径 :param data: data是需要修改的模板变量的字典类型 :param sub: sub是对yml的数据进行二次提取,等于是一个大字典,再提取下一层的小字典,为了让一个yml文件可以有多个接口数据 :return: """ with open(path, encoding="utf-8") as f: if sub is None: ''' 不需要对数据进行二次提取,Template(f.read()).substitute(data)先替换变量 yaml.safe_load把yml格式的字符串变成dict类型返回 ''' return yaml.safe_load(Template(f.read()).substitute(data)) else: ''' 由于Template需要替换全部的变量,有漏的就会报错,先写Template(f.read()).substitute(data) 就会报错,data只对sub下一层的数据改,并没有改其他层的数据,肯定会报错 需要先yaml.safe_load(f)[sub]提取到下一层的数据,但由于是dict 要通过yaml.dump转化成yml格式的字符串,经过Template来改变变量,最后在yaml.safe_load转化成dict ''' return yaml.safe_load( Template(yaml.dump( yaml.safe_load(f)[sub])).substitute(data)) # 错误的写法:return yaml.safe_load(Template(f.read()).substitute(data)) # def send_api_data(self, path, p_data, sub): """ 1.进一步优化封装请求,是本框架的第二个核心技术要点 2.解决了如何非必填字段的问题,接口测试的非必填字段,只需要传入None值就好 2.1 本方法就是解决如何传入None的问题 :param path: 存放yml的api数据的相对路径 :param p_data: Template模板里面,二次转化的数据 :param sub: yml的二级数据目录,区别同一个api类中不同的api方法,比如add,delete :return: 返回请求体的字典类型 """ # 链接根路径和yml文件的相对路径,简化文件路径 path = os.path.join(self.Base_Path, path) # 获取请求数据 data: dict = self.template(path, p_data, sub) log.info(f"api模板改变的参数为:{p_data}") # 由于Template转化的数据都是字符串,None也会变成'None',通过下面的方法解决这个问题 # 防止有些请求没有请求体的,不然就报错了 try: for i in data['json'].keys(): if data['json'][i] == 'None': data['json'][i] = None except: pass log.info(f"修改后的请求为:{data}") res = self.send_api(data) log.info((f"响应为:{res}")) return res
class WSchedule(BaseApi): """ 企业微信日程中的日程模块的API类 secret:日历的秘钥 token:日历的token yml_api_path: yml api数据的相对路径 """ # 通过配置文件获取日历的secret,token只是为了测试方法,其实不应该存在的 secret = cf.get_key("wwork", "schedule_secret") token = Wework().get_token(secret) # yml api数据的相对路径 data_path = "data/schedule/schedule/schedule_api.yml" def get_schedule_id_list(self): """ 通过数据库,获取日程id的值,日程id的值无法通过接口获取,所以就保存在数据库中 :return: 返回全部的日历程id的列表 """ # 执行sql语句获取日历id的元祖 schedule_id_list = sql.select("select schedule_id from schedule_id") # 把元祖转化成列表 schedule_id_list = [i[0] for i in schedule_id_list] return schedule_id_list def add_schedule(self, token, organizer, start_time, end_time, userid, summary, description, location): """ 增加日程 :param token: access_token的值 :param organizer: 请求参数的值 :param start_time: 请求参数的值 :param end_time: 请求参数的值 :param userid: 请求参数的值 :param summary: 请求参数的值 :param description: 请求参数的值 :param location: 请求参数的值 :return: 返回响应体 """ # 时间传入时间戳,get_time可以将时间字符串转化成时间戳,自己封装的 start_time = self.get_time(start_time) end_time = self.get_time(end_time) # Template模板需要二次改变的值 p_data = { "ip": self.ip, "token": token, "organizer": organizer, "start_time": start_time, "end_time": end_time, "userid": userid, "summary": summary, "description": description, "location": location } res = self.send_api_data(self.data_path, p_data, "add") try: schedule_id = res["schedule_id"] # 当cal_id获取到了,就把schedule_id放到数据库中 sql.insert( f"insert into schedule_id(userid,schedule_id) values('{organizer}','{schedule_id}')" ) except KeyError as e: log.error("响应不正确,无法插入数据") return res def delete_schedule(self, token, index): """ 删除日程 :param token: 日历的token值 :param index: 在数据库获取第几个id值 :return: 返回响应体 """ # 从数据库获取schedule_id schedule_id = self.get_schedule_id_list()[index] p_data = {"ip": self.ip, "token": token, "schedule_id": schedule_id} res = self.send_api_data(self.data_path, p_data, "delete") # 当删除api成功时,同步从数据库中删除schedule_id if res["errcode"] == 0: sql.delete( f"delete from schedule_id where schedule_id='{schedule_id}'") else: log.info("删除请求失败,无法删除schedule_id") return res def get_schedule(self, token, index=None): """ 获取日程信息 :param token: 日程的token值 :param index: 在数据库获取第几个id值 :return: 返回响应体 """ # 解决index存在的时候,传的schedule_id_list不是一个列表 schedule_id_list = [] # 从数据库获取schedule_id_list,才能查询日历 if index is None: schedule_id_list = self.get_schedule_id_list() else: schedule_id_list.append(self.get_schedule_id_list()[index]) p_data = { "ip": self.ip, "token": token, "schedule_id_list": schedule_id_list } res = self.send_api_data(self.data_path, p_data, "get") return res def edit_schedule(self, token, organizer, index, start_time, end_time, userid, summary, description, location): """ :param token: 日程的token值 :param organizer: 请求参数的值 :param index: 请求参数的值 :param start_time: 请求参数的值 :param end_time: 请求参数的值 :param userid: 请求参数的值 :param summary: 请求参数的值 :param description: 请求参数的值 :param location: 请求参数的值 :return: """ # 从数据库获取schedule_id schedule_id = self.get_schedule_id_list()[index] start_time = self.get_time(start_time) end_time = self.get_time(end_time) p_data = { "ip": self.ip, "token": token, "organizer": organizer, "schedule_id": schedule_id, "start_time": start_time, "end_time": end_time, "userid": userid, "summary": summary, "description": description, "location": location } res = self.send_api_data(self.data_path, p_data, "edit") return res
class Member(BaseApi): """ 通讯录的api类,比较low的代码展示,其他api类在不断完善中 env_ip:测试环境的ip,都可以放到父类 BASE_PATH:根路径,都可以放到父类 """ # 定义不同测试、生产环境的ip,通过配置文件获取 # 但是这里并没有用到,是比较老的api代码了 env_ip = cf.get_key("env", "formal_ip") # 定义项目的绝对根路径 BASE_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) # def send_api_data(self, p_data, path): """ 封装从yml拿数据,并改变替换yml原本的$变量的数据 :param p_data: Template二次转化的变量数据 :param path: yml_api的路径 :return: """ # 打印传入template要改变的$变量值 log.info(f"template传入的p_data:{p_data}") # 读取yml文件的路径 data_path = os.path.join(self.BASE_PATH, path) # 改变yml文件的$变量值 data = self.template(data_path, p_data) log.info(f"请求的所有参数:{data}") # 获取响应体 res = self.send_api(data) return res def add_member(self, token, userid, name, mobile): """ 增加联系人,这里代码没有封装,看起来很乱 :param token: token值 :param userid: 请求参数的值 :param name: 请求参数的值 :param mobile: 请求参数的值 :return: 返回响应体 """ # Template模板二次修改的值,p_data p_data = { "token": token, "name": name, "userid": userid, "mobile": mobile } # 合并yml_api的文件路径 data_path = os.path.join(self.BASE_PATH, "data/member/add_member.yml") # 通过模板技术获取更改后的请求数据 data = self.template(data_path, p_data) # log日志打印请求体 log.info(data) # 发送封装requests的请求,获取响应值 res = self.send_api(data) return res def get_invite_qr(self, token, size_type): """ 获取企业微信邀请二维码,代码进行了优化缩减,使用了send_api_data进一个封装代码 :param token: token值 :param size_type: 二维码尺寸大小 :return: 返回响应体 """ p_data = {"token": token, "size_type": size_type} res = self.send_api_data(p_data, "data/member/get_invite_qr.yml") """ 这四行代码用上面的两行代码搞定了 p_data = {"token": token, "size_type": size_type} data_path = os.path.join(self.BASE_PATH, "data/member/get_invite_qr.yml") data = self.base.template(data_path, p_data) res = self.send_api(data) """ return res # 获取企业微信活跃数 def get_active_stat(self, token, date): p_data = {"ip": self.env_ip, "token": token, "date": date} res = self.send_api_data(p_data, "data/member/get_active_stat.yml") return res # 获取企业微信用户数 def get_member_info(self, token, userid): p_data = {"token": token, "userid": userid} data_path = os.path.join(self.BASE_PATH, "data/member/get_member.yml") data = self.template(data_path, p_data) res = self.send_api(data) return res # 编辑联系人 def edit_member(self, token, userid, name, mobile): p_data = { "token": token, "name": name, "userid": userid, "mobile": mobile } data_path = os.path.join(self.BASE_PATH, "data/member/edit_member.yml") data = self.template(data_path, p_data) res = self.send_api(data) return res # 删除联系人 def delete_member(self, token, userid): p_data = {"token": token, "userid": userid} data_path = os.path.join(self.BASE_PATH, "data/member/delete_member.yml") data = self.template(data_path, p_data) log.info(f"请求的参数:{data}") res = self.send_api(data) return res # 批量删除联系人 def multi_delete_member(self, token, uesrid_list): p_data = {"token": token, "userid_list": uesrid_list} data_path = os.path.join(self.BASE_PATH, "data/member/multi_delete_member.yml") data = self.template(data_path, p_data) res = self.send_api(data) return res # 获取部门的联系人信息 def get_depart_member(self, token, department_id, fetch_child): p_data = { "token": token, "department_id": department_id, "fetch_child": fetch_child } log.info(p_data) data_path = os.path.join(self.BASE_PATH, "data/member/get_depart_member.yml") data = self.template(data_path, p_data) log.info(data) res = self.send_api(data) return res # 获取部门详细的联系人信息 def get_depart_member_explicit(self, token, department_id, fetch_child): p_data = { "token": token, "department_id": department_id, "fetch_child": fetch_child } log.info(p_data) data_path = os.path.join(self.BASE_PATH, "data/member/get_depart_member_explicit.yml") data = self.template(data_path, p_data) log.info(data) res = self.send_api(data) return res
def token(): secret = cf.get_key("wwork", "meeting_room_secret") token = Wework().get_token(secret) return token
def schedule_token(): schedule_secret = cf.get_key("wwork", "schedule_secret") token = Wework().get_token(schedule_secret) return token
class TestMember(): # 通过配置文件获取联系人的secret contact_secret = cf.get_key("wwork", "contact_secret") # 获取access_token token = Wework().get_token(contact_secret) # 初始化member的api对象 member = Member() ''' 这样获取数据的方法,要读取两次文件,速度太慢了 add_data = member.load_yaml("data/member/member_para_data.yml")['add']['data'] add_ids = member.load_yaml("data/member/member_para_data.yml")['add']['ids'] ''' # 参数化的数据 para_data = member.load_yaml("data/member/member_para_data.yml") # 删除用例的参数化数据和ids标题数据 delete_data = para_data['delete']['data'] delete_ids = para_data['delete']['ids'] # 删除用例的参数化数据和ids标题数据 multi_delete_data = para_data['multi_delete']['data'] multi_delete_ids = para_data['multi_delete']['ids'] # 删除用例的参数化数据和ids标题数据 add_data = para_data['add']['data'] add_ids = para_data['add']['ids'] # 删除用例的参数化数据和ids标题数据 edit_data = para_data['edit']['data'] edit_ids = para_data['edit']['ids'] # 删除用例的参数化数据和ids标题数据 get_data = para_data['get']['data'] get_ids = para_data['get']['ids'] # 删除用例的参数化数据和ids标题数据 active_data = para_data['active']['data'] active_ids = para_data['active']['ids'] # 删除用例的参数化数据和ids标题数据 qr_data = para_data['qr']['data'] qr_ids = para_data['qr']['ids'] # 删除用例的参数化数据和ids标题数据 depart_simple_data = para_data['depart_simple']['data'] depart_simple_ids = para_data['depart_simple']['ids'] # 删除用例的参数化数据和ids标题数据 depart_explicit_data = para_data['depart_explicit']['data'] depart_explicit_ids = para_data['depart_explicit']['ids'] # # def setup_class(self,): # print("abc") @allure.severity(allure.severity_level.CRITICAL) @allure.story("增加联系人") @pytest.mark.parametrize(("userid,name,mobile,errcode,errmsg"), add_data, ids=add_ids) def test01_add_member(self, userid, name, mobile, errcode, errmsg, add): log.info(f"-------开始测试增加成员-------") res = self.member.add_member(self.token, userid, name, mobile) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.CRITICAL) @allure.story("获得联系人信息") @pytest.mark.parametrize(("userid,errcode,errmsg"), get_data, ids=get_ids) def test02_get_member(self, userid, errcode, errmsg, get): log.info("-------开始测试获取成员-------") res = self.member.get_member_info(self.token, userid) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.CRITICAL) @allure.story("删除联系人") @pytest.mark.parametrize(("userid,errcode,errmsg"), delete_data, ids=delete_ids) def test04_delete_member(self, userid, errcode, errmsg, delete): log.info("-------开始测试获取成员-------") res = self.member.delete_member(self.token, userid) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.CRITICAL) @allure.story("批量删除联系人") @pytest.mark.parametrize(("userid_list,errcode,errmsg"), multi_delete_data, ids=multi_delete_ids) def test05_multi_delete_member(self, userid_list, errcode, errmsg, multi_delete): log.info("-------开始批量删除获取成员-------") res = self.member.multi_delete_member(self.token, userid_list) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.CRITICAL) @allure.story("编辑联系人") @pytest.mark.parametrize(("userid,name,mobile,errcode,errmsg"), edit_data, ids=edit_ids) def test03_edit_member(self, userid, name, mobile, errcode, errmsg, edit): log.info("-------开始修改获取成员-------") res = self.member.edit_member(self.token, userid, name, mobile) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.NORMAL) @allure.story("查看企业微信活跃度") @pytest.mark.parametrize(("date,errcode,errmsg"), active_data, ids=active_ids) def test_active_stat(self, date, errcode, errmsg): log.info("-------开始查看企业微信活跃度-------") res = self.member.get_active_stat(self.token, date) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.NORMAL) @allure.story("增加联系人") @pytest.mark.parametrize(("size,errcode,errmsg"), qr_data, ids=qr_ids) def test_get_invite_qr(self, size, errcode, errmsg): log.info("-------开始获取企业微信二维码-------") res = self.member.get_invite_qr(self.token, size) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.CRITICAL) @allure.story("查看部门联系人的简单信息") @pytest.mark.parametrize(("department_id,fetch_child,errcode,errmsg"), depart_simple_data, ids=depart_simple_ids) def test_get_depart_member(self, department_id, fetch_child, errcode, errmsg): log.info("-------开始获取部门成员简单的信息-------") res = self.member.get_depart_member(self.token, department_id, fetch_child) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.CRITICAL) @allure.story("查看部门联系人的复杂信息") @pytest.mark.parametrize(("department_id,fetch_child,errcode,errmsg"), depart_explicit_data, ids=depart_explicit_ids) def test_get_depart_member_explict(self, department_id, fetch_child, errcode, errmsg): log.info("-------开始部门成员详细信息-------") res = self.member.get_depart_member_explicit(self.token, department_id, fetch_child) log.info(f"打印响应结果:{res}") log.info("-------测试结束-------") assert res["errcode"] == errcode assert errmsg in res["errmsg"] @allure.severity(allure.severity_level.BLOCKER) @allure.story("增加联系人") @pytest.mark.smoke def test_all_smoke_member(self, test_all_pre_data): add_res = self.member.add_member(self.token, "tong1234", "tong1234", "13172771165") edit_res = self.member.edit_member(self.token, "tong1234", "tong1234", "13172771165") del_res = self.member.delete_member(self.token, "tong1234") multi_del_res = self.member.multi_delete_member( self.token, ["tongtong1", "tongtong2", "tongtong3"]) qr_res = self.member.get_invite_qr(self.token, 1) active_res = self.member.get_active_stat(self.token, "2020-10-10") depart_res = self.member.get_depart_member(self.token, "1", "1") depart_res_e = self.member.get_depart_member_explicit( self.token, "1", "1") assert add_res["errcode"] == 0 assert edit_res["errcode"] == 0 assert del_res["errcode"] == 0 assert multi_del_res["errcode"] == 0 assert qr_res["errcode"] == 0 assert active_res["errcode"] == 0 assert depart_res["errcode"] == 0 assert depart_res_e["errcode"] == 0 log.info("finish") def tear_down(self): pass
class Member(BaseApi): # 定义不同测试、生产环境的ip,通过配置文件获取 env_ip = cf.get_key("env", "formal_ip") # 定义项目的绝对根路径 BASE_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) # 封装从yml拿数据,并改变替换yml原本的$变量的数据 def send_api_data(self, p_data, path): # 打印传入template要改变的$变量值 log.info(f"template传入的p_data:{p_data}") # 读取yml文件的路径 data_path = os.path.join(self.BASE_PATH, path) # 改变yml文件的$变量值 data = self.template(data_path, p_data) log.info(f"请求的所有参数:{data}") res = self.send_api(data) return res def add_member(self, token, userid, name, mobile): p_data = { "token": token, "name": name, "userid": userid, "mobile": mobile } data_path = os.path.join(self.BASE_PATH, "data/member/add_member.yml") data = self.template(data_path, p_data) log.info(data) res = self.send_api(data) return res def get_member_info(self, token, userid): p_data = {"token": token, "userid": userid} data_path = os.path.join(self.BASE_PATH, "data/member/get_member.yml") data = self.template(data_path, p_data) res = self.send_api(data) return res def edit_member(self, token, userid, name, mobile): p_data = { "token": token, "name": name, "userid": userid, "mobile": mobile } data_path = os.path.join(self.BASE_PATH, "data/member/edit_member.yml") data = self.template(data_path, p_data) res = self.send_api(data) return res def delete_member(self, token, userid): p_data = {"token": token, "userid": userid} data_path = os.path.join(self.BASE_PATH, "data/member/delete_member.yml") data = self.template(data_path, p_data) log.info(f"请求的参数:{data}") res = self.send_api(data) return res def multi_delete_member(self, token, uesrid_list): p_data = {"token": token, "userid_list": uesrid_list} data_path = os.path.join(self.BASE_PATH, "data/member/multi_delete_member.yml") data = self.template(data_path, p_data) res = self.send_api(data) return res def get_depart_member(self, token, department_id, fetch_child): p_data = { "token": token, "department_id": department_id, "fetch_child": fetch_child } log.info(p_data) data_path = os.path.join(self.BASE_PATH, "data/member/get_depart_member.yml") data = self.template(data_path, p_data) log.info(data) res = self.send_api(data) return res def get_depart_member_explicit(self, token, department_id, fetch_child): p_data = { "token": token, "department_id": department_id, "fetch_child": fetch_child } log.info(p_data) data_path = os.path.join(self.BASE_PATH, "data/member/get_depart_member_explicit.yml") data = self.template(data_path, p_data) log.info(data) res = self.send_api(data) return res def get_invite_qr(self, token, size_type): p_data = {"token": token, "size_type": size_type} res = self.send_api_data(p_data, "data/member/get_invite_qr.yml") # p_data = {"token": token, "size_type": size_type} # data_path = os.path.join(self.BASE_PATH, "data/member/get_invite_qr.yml") # data = self.base.template(data_path, p_data) # res = self.send_api(data) return res def get_active_stat(self, token, date): p_data = {"ip": self.env_ip, "token": token, "date": date} res = self.send_api_data(p_data, "data/member/get_active_stat.yml") return res
def get_token(self): secret = cf.get_key("wwork", "contact_secret") access_token = Wework().get_token(secret) return access_token
class MeetingRoom(BaseApi): """ 会议室的api类 test_token: token值 api_path: yml_api的相对路径 """ # 只是拿来测试用,可以不存在在这里 test_token = Wework().get_token(cf.get_key("wwork", "meeting_room_secret")) # 简化send_api_data方法路径引用,不用写那么多路径了 api_path = "data/meeting_room/meeting_room_api.yml" # 增加会议室 def add_meeting_room(self, token, name, capacity, city, building, floor, equipment): # Template模板二次修改的值,p_data p_data = { "ip": self.ip, "token": token, "name": name, "capacity": capacity, "city": city, "building": building, "floor": floor, "equipment": equipment } # 获取响应,进行了多次封装 res = self.send_api_data(self.api_path, p_data, "add") return res # 编辑会议室 def edit_meeting_room(self, token, meetingroom_id, name, capacity, city, building, floor, equipment): p_data = { "ip": self.ip, "token": token, "meetingroom_id": meetingroom_id, "name": name, "capacity": capacity, "city": city, "building": building, "floor": floor, "equipment": equipment } res = self.send_api_data(self.api_path, p_data, "edit") return res # 删除会议室 def delete_meeting_room(self, token, meetingroom_id): p_data = { "ip": self.ip, "token": token, "meetingroom_id": meetingroom_id } res = self.send_api_data(self.api_path, p_data, "delete") return res # 获取会议室 def get_meeting_room(self, token, city, building, floor, equipment): p_data = { "ip": self.ip, "token": token, "city": city, "building": building, "floor": floor, "equipment": equipment } res = self.send_api_data(self.api_path, p_data, "get") return res