【自总结Python自动化】之自动化测试框架套用模板(WEB、APP、接口)
目录
一、目录模板 返回目录
有以下常用的模块可以套用WEB自动化和APP自动化
# 主要模块
-- 项目名称
-- page_object
-- data
-- locator
-- page
-- test(自己备用的,可以忽略)
-- test_case
-- utils
二、创建启动APP或WEB文件 返回目录
1、启动app.py
from appium import webdriver
from Appium_20210407.pageObject.page.main_page import MainPage
from Appium_20210407.pageObject.utils.functions import Functions as Fun
class APP(object): appData = Fun().getYamlData('app') caps = appData['caps'] server = appData['server'] ip = server['ip'] port = server['port'] def startApp(self): """启动APP""" self.driver = webdriver.Remote(f"http://{self.ip}:{self.port}/wd/hub", self.caps) self.driver.implicitly_wait(15) return self def stopApp(self): """关闭APP""" self.driver.quit() def goto_main(self): """跳转主页""" return MainPage(self.driver)
①获取package和activity:
adb shell dumpsys activity | grep LAUNCHER
②app对应caps参数:
caps: platformName: "android" deviceName: "emulator-5554" appPackage: "com.tencent.wework" appActivity: ".launch.LaunchSplashActivity" noReset: True skipServerInstallation: True # 跳过UIautomator2 server安装 skipDeviceInitialization: True # 跳过设备的初始化 # waitForIdleTimeout: 1 # automationName: "UiAutomator2" # Toast内容 # dontStopAppOnReset: True # 测试之前不停止app运行 server: ip: 127.0.0.1 port: 4723
③对应的方法文件
import os
import yaml
class Functions: def pathUp(self): """获取上级路径""" path = os.path.dirname(os.path.dirname(__file__)) return path def getYaml(self,path): """获得yaml数据""" with open(path,encoding='utf-8') as file: data = yaml.load(file) return data def getCommonYaml(self): """获得公共yaml数据""" commonPath = self.pathUp()+ "/data/common.yaml" return self.getYaml(commonPath) def getYamlData(self,data): """获取当前的yaml数据""" yamlPath = self.pathUp() + self.getCommonYaml()[data] return self.getYaml(yamlPath)
2、启动web.py
from selenium import webdriver from page_object.page.login_page import LoginPage from page_object.utils.functions import Functions as Fun class Web: def startWeb(self,url): """开启WEB自动化""" basePath = Fun().upPath() self.driver = webdriver.Chrome(basePath + "/utils/chromedriver") self.driver.get(url) self.driver.maximize_window() self.driver.implicitly_wait(10) return self def stopWeb(self): """关闭浏览器""" self.driver.quit() def goto_loginPage(self): """跳转登录页""" return LoginPage(self.driver)
①对应的方法文件1:
import base64 import os import random import re import time import pyautogui import yaml import pyperclip import cv2 import numpy from io import BytesIO from PIL import Image from pykeyboard import PyKeyboard from pymouse import PyMouse class Functions(): def curPath(self): """获取本层目录""" basePath = os.path.dirname(os.path.abspath(__file__)) return basePath def upPath(self): """获取上级目录路径""" basePath = os.path.dirname(os.path.dirname(__file__)) return basePath def getYamlData(self,yamlName): """获取yaml数据""" yamlPath = self.upPath() + f'/data/{yamlName}Data.yaml' with open(yamlPath,encoding='utf-8') as file: data = yaml.load(file,Loader=yaml.FullLoader) return data[yamlName] def getIndex(self, type, name): """获取区级对应角标index""" list = self.getYamlData('selectData')[type] for index, value in enumerate(list): if name in value: return index + 1 def upload_file(self, fileName): """PyUserInput方法:上传文件""" # 创建鼠标对象 k = PyKeyboard() # 创建键盘对象 m = PyMouse() # 模拟快捷键Command+Shift+G k.press_keys(["Command", "Shift", "G"]) # 输入文件路径 x_dim, y_dim = m.screen_size() # //点击屏幕中间,除法取整数 m.click(x_dim // 2, y_dim // 2, 1) # 点击,想x,y坐标,button:-1表示左键,-2表示右键,n:默认1次,2双击 # 复制文件文件全路径 pyperclip.copy(fileName) # 粘贴路径,模拟快捷键Command+V k.press_keys(["Command", "V"]) k.tap_key("Shift") # 加上这个之后才能点击回车(未知情况) for i in range(2): k.press_key("return") time.sleep(2) def upload_file1(self, path): """PyUserInput方法1""" # 创建鼠标对象 k = PyKeyboard() # 创建键盘对象 m = PyMouse() filepath = "/" # 模拟快捷键Command+Shift+G k.press_keys(["Command", "Shift", "G"]) # 输入文件路径 x_dim, y_dim = m.screen_size() m.click(x_dim // 2, y_dim // 2, 1) # 复制文件路径开头的斜杠/ pyperclip.copy(filepath) # 粘贴斜杠/ k.press_keys(["Command", "V"]) time.sleep(2) # 输入文件全路径进去 k.type_string(path) fileName = '机构信息-批量导入模板 (9).xls' pyperclip.copy(fileName) k.press_keys(["Command", "V"]) time.sleep(2) k.press_key("Return") time.sleep(2) k.press_key("Return") time.sleep(2) def upload_file2(self, path): """pyautogui方法【不用】""" filepath = "/" pyautogui.press('shiftleft') pyautogui.hotkey("Command", "Shift", "G") pyautogui.typewrite(path, interval=0.25) pyautogui.press('return') time.sleep(2) pyautogui.press('return') time.sleep(2) def base64_to_image(self,base64_str , image_path=None): """在第一步里:base64转化为image""" base64_data = re.sub('^data:image/.+;base64,', '', base64_str) byte_data = base64.b64decode(base64_data) image_data = BytesIO(byte_data) img = Image.open(image_data) if image_path: img.save(image_path) return img def match_gaps(self, full, gap): """第二步:匹配缺口照片在完整照片的位置""" # 读取图片文件信息 img_full = cv2.imread(full) # 以灰度模式加载图片 template = cv2.imread(gap) # 方法 methods = [cv2.TM_SQDIFF_NORMED, cv2.TM_CCORR_NORMED, cv2.TM_CCOEFF_NORMED] # 记录每个方法的距离 left = [] # 最接近值 min_ = [] for method in methods: # 匹配 res = cv2.matchTemplate(img_full, template, method) # 获取相关内容 min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) if method == cv2.TM_SQDIFF_NORMED: min_.append(min_val - 0.0) left.append(min_loc[0]) else: min_.append(1.0 - max_val) left.append(max_loc[0]) index = min_.index(numpy.min(min_)) print("选用第{:d}个方法, 差为:{:f},距离为:{:d}".format(index+1, min_[index], left[index])) return left[index] def get_track(self, distance): """在第三步里:滑块移动轨迹""" track = [] current = 0 # 阈值 mid = distance * 3 / 4 t = random.randint(5, 6) / 10 v = 0 while current < distance: if current < mid: a = 6 else: a = -7 v0 = v v = v0 + a * t move = v0 * t + 3 / 4 * a * t * t current += move track.append(round(move)) return track
②对应的方法文件2:
import os import yaml class Functions: def curPath(self): """获取本层目录""" basePath = os.path.dirname(os.path.abspath(__file__)) return basePath def upPath(self): """获取上级目录路径""" basePath = os.path.dirname(os.path.dirname(__file__)) return basePath def getYamlData(self,yamlName): """获取yaml数据""" yamlPath = self.upPath() + f'/data/{yamlName}Data.yaml' with open(yamlPath,encoding='utf-8') as file: data = yaml.load(file,Loader=yaml.FullLoader) return data[yamlName]
三、创建base_page文件 返回目录
1、app自动化base
from appium.webdriver.webdriver import WebDriver
class Page: def __init__(self,driver:WebDriver): self.driver = driver def find_element(self,loc): """查找单元素""" return self.driver.find_element(*loc) def find_elements(self,loc): """查找多元素""" return self.driver.find_elements(*loc) def el_sendKeys(self,loc,text): """输入事件""" self.find_element(loc).send_keys(text) def el_click(self,loc): """点击事件""" self.find_element(loc).click() def swipeUp(self,loc): """上滑操作""" size = self.driver.get_window_size() width = size['width'] height = size['height'] while(True): try: # ele = self.driver.find_element(MobileBy.XPATH,loc) ele = self.find_element(loc) return ele except: print("继续上滑") self.driver.swipe(0.5 * width, 0.7 * height, 0.5 * width, 0.3 * height)
2、web自动化base
import time from selenium.webdriver.chrome.webdriver import WebDriver from selenium import webdriver from selenium.webdriver.support.select import Select from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.action_chains import ActionChains as AC class Base: def __init__(self, driver: WebDriver): self.driver = driver # def __init__(self,webdriver): # """正式运行代码用""" # self.driver = webdriver # self.timeout = 10 def find_element(self, loc): """查找元素""" return self.driver.find_element(*loc) def find_elements(self, loc): """查找多组元素""" return self.driver.find_elements(*loc) def el_click(self, loc): """点击单元素事件""" self.webDriverWait(loc).click() def els_click_index(self, loc, index): """点击多元素事件:坐标点""" self.webDriverWaits(loc)[index-1].click() def els_click(self, loc, name): """点击多元素事件:元素""" list = self.webDriverWaits(loc) for i in list: if name == i.text: i.click() time.sleep(2) def el_sendKeys(self, loc, text): """输入事件""" self.webDriverWait(loc).send_keys(text) def webDriverWait(self, loc): """显式等待,查找单元素""" WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located(loc)) return self.find_element(loc) def webDriverWaits(self, loc): """显式等待,查找多元素""" WebDriverWait(self.driver, 10).until(EC.visibility_of_all_elements_located(loc)) return self.find_elements(loc) def handles(self): """获取所有页面handles""" return self.driver.window_handles def enter_window(self, index): """进入页面""" handles = self.handles() self.driver.switch_to.window(handles[index-1]) def get_text(self, loc): """获取文字内容""" return self.webDriverWait(loc).text def move_to_element(self, loc): """移动鼠标到元素上""" AC(self.driver).move_to_element(self.webDriverWait(loc)).perform() def move_by_offset(self, t): """拖动鼠标对元素执行位移""" AC(self.driver).move_by_offset(xoffset=t, yoffset=0).perform() def release(self): """在元素上松开鼠标""" AC(self.driver).release().perform() def click_and_hold(self, loc): """鼠标左键单击,不松开""" AC(self.driver).click_and_hold(self.webDriverWait(loc)).perform() def el_clear(self, loc): """清空数据""" self.webDriverWait(loc).clear() def el_clear_sendKeys(self, loc, text): """清空数据并输入数据""" self.webDriverWait(loc).clear() self.el_sendKeys(loc, text) def el_select(self, loc, text): """select下拉框选择元素""" Select(self.webDriverWait(loc)).select_by_visible_text(text) def executeScript(self, js, loc): """执行JS元素""" if loc == None: return self.driver.execute_script(js) else: return self.driver.execute_script(js, self.webDriverWait(loc)) def el_clickBoxView(self, loc): """点击下拉框隐藏的元素""" self.webDriverWait(loc).location_once_scrolled_into_view self.el_click(loc)
四、关联每个页面跳转 返回目录
1、举例web自动化
①web启动页跳转到登录页
from selenium import webdriver from page_object.page.login_page import LoginPage from page_object.utils.functions import Functions as Fun class Web: def startWeb(self): """开启WEB自动化""" # 分拣中心地址 loginData = Fun().getYamlData("login")['sort'] # 运营后台地址 # loginData = Fun().getYamlData("login")['operate'] basePath = Fun().upPath() self.driver = webdriver.Chrome(basePath + "/utils/chromedriver") self.driver.get(loginData['url']) self.driver.maximize_window() self.driver.implicitly_wait(10) return self def stopWeb(self): """关闭浏览器""" self.driver.quit() def goto_loginPage(self): """跳转登录页""" return LoginPage(self.driver)
②登录页跳转到首页
from page_object.page.base_page import Base from page_object.locator.loginPage_loc import LoginPageLoc as loc from page_object.page.main_page import MainPage from page_object.utils.track import Track class LoginPage(Base): def login_action(self): """登录操作""" self.el_click(loc.operator_loc) self.el_click(loc.operatorName_loc) self.el_clear_sendKeys(loc.username_loc, loc.usernameData) self.el_clear_sendKeys(loc.password_loc, loc.passwordData) self.el_click(loc.loginButton_loc) Track(self.driver).loop() def goto_mainPage(self): """跳转到主页""" self.login_action() return MainPage(self.driver)
③首页跳转到承包商用户管理页面
from page_object.page.base_page import Base from page_object.locator.mainPage_loc import MainPageLoc as loc from page_object.page.contractor_page import ContractorPage class MainPage(Base): def goto_contractorPage(self): """跳转到承包商用户管理页面""" self.el_click(loc.left_operator_loc) return ContractorPage(self.driver)
④管理页面进行新增操作和注销操作等
from time import sleep from page_object.page.base_page import Base from page_object.locator.contractorPage_loc import ContractorPageLoc as loc from page_object.utils.functions import Functions as Fun class ContractorPage(Base): def uploadImg(self, imgLoc, imgName): """上传图片文件""" self.el_click(imgLoc) Fun().upload_file(loc.filePathData + imgName) sleep(5) def addContractor_action(self): """新增承包商操作""" # 点击新增按钮 self.el_click(loc.addContractorButton_loc) # 填写新增信息 self.el_clear_sendKeys(loc.mobile_loc, loc.mobile) self.uploadImg(loc.portraitFace_loc, loc.portraitFace) self.uploadImg(loc.nationalEmblemFace_loc, loc.nationalEmblemFace) self.el_select(loc.province_loc, loc.province) self.el_select(loc.city_loc, loc.city) self.el_select(loc.district_loc, loc.district) self.el_clear_sendKeys(loc.detaiAddress_loc, loc.detaiAddress) self.el_clear_sendKeys(loc.emerContact_loc, loc.emerContact) self.el_clear_sendKeys(loc.emerContactMobile_loc, loc.emerContactMobile) self.el_click(loc.region_loc) # 下拉框到不可见的元素:JS方法 self.executeScript(loc.regionName_js, loc.regionName3_loc) self.executeScript(loc.regionName_click_js, loc.regionName3_loc) # self.el_clickBoxView(loc.regionName3_loc) # 多元素简写:选择第二个下拉框,20s246ms # self.els_click_index(loc.regionName1_loc, 2) # 坐标点:选择第二个下拉框,22s283ms # self.els_click(loc.regionName2_loc, loc.regionName2) # 多元素方法:选择第二个下拉框,25s624ms self.el_click(loc.sureButton_loc) def logout_action(self): """注销承包商操作""" # 注销 self.el_clear_sendKeys(loc.queryMobile_loc, loc.mobile) self.el_click(loc.queryButton_loc) self.el_click(loc.logoutButton_loc) self.el_clear_sendKeys(loc.logoutReason_loc, loc.logoutReason) self.el_click(loc.logoutOkButton_loc) sleep(10)
五、元素定位文件和yaml数据文件 返回目录
1、创建定位文件
在locator目录下,例如文件1:newOrganPage_loc.py
from selenium.webdriver.common.by import By from page_object.utils.functions import Functions as Fun class NewOrganPageLoc: organData = Fun().getYamlData('organ') provinceLevelArea = organData['provinceLevelArea'] municipalLevelArea = organData['municipalLevelArea'] districtLevelArea = organData['districtLevelArea'] districtName = organData['districtName'] organType = organData['organType'] organTypeName = organData['organTypeName'] addressName = organData['addressName'] fullAddress = organData['fullAddress'] contacts = organData['contacts'] telePhone = organData['telePhone'] explain = organData['explain'] organName = organData['organName'] organCode = organData['organCode'] fullAddressText = organData['fullAddressText'] contactsText = organData['contactsText'] telePhoneText = organData['telePhoneText'] explainText = organData['explainText'] # XX名称 organName_loc = (By.CSS_SELECTOR, ".formtable > form > div:nth-child(1) >div>div>div>input") # XX编码 organCode_loc = (By.CSS_SELECTOR, ".formtable > form > div:nth-child(2) >div>div>div>input") # 单位级别 unitLevel_loc = (By.CSS_SELECTOR, ".formtable > form > div:nth-child(3) >div>div>div>div>input") # 选择XX级别:区级 selectDistrictLevel_loc = (By.XPATH, "//body/div[2]/div/div/ul/li[2]") # 所属行政区:省级地区 provinceLevelArea_loc = (By.XPATH, "//*[@placeholder='{}']".format(provinceLevelArea))# XX地址:区 districtLevel_loc = (By.XPATH, "//*[@placeholder='"+districtLevelArea[0]+"']") # XX地址区级:某某区 TJDistrict2_loc = (By.XPATH, "//body/div[9]/div/div/ul/li["+ str(Fun().getIndex(f'{districtLevelArea}',f'{addressName}')) +"]") # 详细地址 fullAddress_loc = (By.XPATH, f"//*[@placeholder='{fullAddress}']") # 联系人 contacts_loc = (By.XPATH, f"//*[@placeholder='{contacts}']") # 联系电话 telePhone_loc = (By.XPATH, f"//*[@placeholder='{telePhone}']") # 说明 explain_loc = (By.XPATH, f"//*[@placeholder='{explain}']") # XX保存按钮 saveButton_loc = (By.CSS_SELECTOR, ".el-button--primary")
例如文件2:
from selenium.webdriver.common.by import By from page_object.utils.functions import Functions as Fun class ContractorPageLoc: contractorData = Fun().getYamlData('contractor') filePathData = contractorData['filePath'] # 新增承包商按钮 addContractorButton_loc = (By.CSS_SELECTOR, ".handle_list_btn_box_1>button") # 身份证:人像面 portraitFace_loc = (By.CSS_SELECTOR, ".flex_space_between>div>div>div") portraitFace = contractorData['portraitFace'] # 身份证:国徽面 nationalEmblemFace_loc = (By.CSS_SELECTOR, ".flex_space_between>div:nth-child(2)>div>div") nationalEmblemFace = contractorData['nationalEmblemFace'] # 手机号 mobile_loc = (By.CSS_SELECTOR, "form>div:nth-child(2)>div>div>input") mobile = contractorData['mobile'] # 联系地址:省 province_loc = (By.CSS_SELECTOR, "form>div:nth-child(4)>div>div>label:nth-child(1)>select") province = contractorData['province'] # 联系地址:市 city_loc = (By.CSS_SELECTOR, "form>div:nth-child(4)>div>div>label:nth-child(2)>select") city = contractorData['city'] # 联系地址:区 district_loc = (By.CSS_SELECTOR, "form>div:nth-child(4)>div>div>label:nth-child(3)>select") district = contractorData['district'] # 详细地址 detaiAddress_loc = (By.CSS_SELECTOR, ".el-textarea__inner") detaiAddress = contractorData['detaiAddress'] # 紧急联系人 emerContact_loc = (By.CSS_SELECTOR, "form>div:nth-child(6)>div>div>input") emerContact = contractorData['emerContact'] # 紧急联系人手机号 emerContactMobile_loc = (By.CSS_SELECTOR, "form>div:nth-child(7)>div>div>input") emerContactMobile = contractorData['emerContactMobile'] # 所在区域 region_loc = (By.CSS_SELECTOR, "form>div:nth-child(8)>div>div>div>input") regionName1_loc = (By.CSS_SELECTOR, "ul>li>span") regionName2_loc = (By.XPATH, "//ul/li/span") regionName2 = contractorData['regionName'] regionName3_loc = (By.XPATH, f"//ul/li/span[contains(text(),'{regionName2}')]") regionName_js = "arguments[0].scrollIntoView(false);" regionName_click_js = "arguments[0].click();" # 确定按钮 sureButton_loc = (By.CSS_SELECTOR, ".el-button--primary") # 手机号查询框 queryMobile_loc = (By.CSS_SELECTOR, "div.top.flex.flex_wrap>div:nth-child(1)>div>input") # 查询按钮 queryButton_loc = (By.CSS_SELECTOR, "button.el-button.cancel.el-button--primary.el-button--small") # 注销承包商按钮 logoutButton_loc = (By.CSS_SELECTOR, "tr>td:nth-child(9)>div>button:nth-child(3)") # 注销理由 logoutReason_loc = (By.CSS_SELECTOR, ".el-textarea__inner") logoutReason = contractorData['logoutReason'] # 注销确定按钮 logoutOkButton_loc = (By.CSS_SELECTOR, "span.dialog-footer>button:nth-child(2)")
2、相关yaml数据读取文件:
①这一种适用于下拉框的数据选择
区级地区: - 请选择 - 和平区 - 河东区 - 河西区 - 南开区 - 河北区 - 红桥区 - 东丽区 - 西青区 - 津南区 - 北辰区 - 武清区 - 宝坻区 - 滨海新区 - 宁河区 - 静海区 - 蓟州区 XX类型: - 卫生事业 - 国家机关 - 教育事业 - 文化事业 - 科技事业 - 体育事业 - 团体组织 - 其他 区域: - 省级地区 - 市级地区 - 区级地区
并结合下面的方法:
def getIndex(self,type,name): """获取区级对应角标index""" list = self.getYamlData('selectData')[type] for index,value in enumerate(list): if name in value: return index+1
②普通yaml格式
organName: XX51201 organCode: jg51201 provinceLevelArea: 省级地区 municipalLevelArea: 市级地区 districtLevelArea: 区级地区 districtName: 滨海新区 # 经常改的 organType: 请选择XX类型 organTypeName: 其他 # 经常改的 addressName: 蓟州区 # 经常改的 fullAddress: 请输入详细地址 fullAddressText: 蓟州区黄崖关 contacts: 请输入联系人 contactsText: zc联系人 telePhone: 请您输入手机号 telePhoneText: 136420xxxxx explain: 请输入说明 (100字以内) explainText: zcXX说明
六、创建测试用例 返回目录
1、web自动化
①基础用例
from page_object.page.web import Web class BaseTestCase: def setup(self): self.web = Web().startWeb() self.login = self.web.goto_loginPage() self.main = self.login.goto_mainPage() def teardown(self): self.web.stopWeb()
②测试用例
from page_object.test_case.baseTestCase import BaseTestCase class TestContractorTestCase(BaseTestCase): def test_addContractor(self): """新增承包商测试用例""" # self.main.goto_contractorPage().addContractor_action() self.login.login_action() def test_logoutContractor(self): """注销承包商测试用例""" contractorPage = self.main.goto_contractorPage() contractorPage.addContractor_action() contractorPage.logout_action()
2、app自动化
from Appium_20210407.pageObject.page.app import APP class TestUser: def setup(self): self.app = APP().startApp() self.main = self.app.goto_main() def teardown(self): self.app.stopApp() def test_addUser(self): self.main.goto_addressList().goto_addUser().addUser_action()
七、接口自动化目录模板 返回目录
参考我的项目地址:https://github.com/Owen-ET/2021_Python_HogwartsSDE17_Project_Practice/tree/master/API
# 主要模块 -- 项目名称 -- Server/API -- data -- feishu_work --calendar_api --base.py --feishuWorkAddress.py -- test_case --calendar --baseCalendarsTestData.py --testCalendars.py --base_testcase.py -- utils --functions.py
1、calendar_api接口
下面写base和增删改查等等接口
base.py
import requests from API.utils.functions import Functions class Base: def __init__(self): self.s = requests.Session() self.token = self.get_token() self.s.headers = { 'Authorization': f"Bearer {self.token}", 'Content-Type': "application/json; charset=utf-8" } self.baseUrl = self.base['calendarsUrl'] self.list = [] def get_token(self): '''获取token''' self.base = Functions().getYamlData('base') url = self.base['token']['url'] params = self.base['token']['params'] r = self.send('POST',url,json=params).json() return r['tenant_access_token'] def send(self,*args,**kwargs): return self.s.request(*args,**kwargs)
或者多个端多地址写法
import requests from API.utils.functions import Functions class Base: def __init__(self, flag): self.s = requests.Session() self.token = self.get_token(flag) self.s.headers = { 'Authorization': f"{self.token}", 'Content-Type': "application/json; charset=utf-8" } def get_token(self, flag): '''获取token''' self.loginBase = Functions().getYamlData('base') url = self.loginBase['url'] if flag == 1: # flag:1时,登录承包商小程序 params = self.loginBase['contractorLogin']['params'] print(params) elif flag == 2: # flag:2时,登录回收车小程序 params = self.loginBase['recoveryLogin']['params'] print(params) else: params = None r = self.send('POST',url, params=params).json() return r['data']['token'] def send(self,*args,**kwargs): """公共发送请求方法""" return self.s.request(*args,**kwargs)
feishuWorkAddress.py
from API.feishu_work.calendar_api.base import Base class FeishuWorkCalendars(Base): def get_calendarsList_info(self,calendar_id): '''获取日历列表''' url = f'{self.baseUrl}{calendar_id}' # print(self.get_token()) # headers = { # 'Authorization': f"Bearer {self.get_token()}", # 'Content-Type': "application/json; charset=utf-8" # } # r = self.s.get(url).json() r = self.send('GET',url).json() return r def create_calendars(self,summary,description,permissions,color,summary_alias): '''创建日历''' url = f'{self.baseUrl}' # headers = { # 'Authorization': f"Bearer {self.get_token()}", # 'Content-Type': "application/json; charset=utf-8" # } data = { 'summary': summary, 'description': description, 'permissions': permissions, 'color': color, 'summary_alias': summary_alias } r = self.send('POST',url,json=data).json() return r def update_calendars(self,calendar_id,summary,description,permissions,color,summary_alias): '''修改日历''' url = f'{self.baseUrl}{calendar_id}' # headers = { # 'Authorization': f"Bearer {self.get_token()}", # 'Content-Type': "application/json; charset=utf-8" # } data = { 'summary': summary, 'description': description, 'permissions': permissions, 'color': color, 'summary_alias': summary_alias } r = self.send('PATCH',url, json=data).json() return r def delete_calendars(self,calendar_id): '''删除日历''' url = f'{self.baseUrl}{calendar_id}' # headers = { # 'Authorization': f"Bearer {self.get_token()}", # 'Content-Type': "application/json; charset=utf-8" # } r = self.send('DELETE',url).json() return r def delete_error_calendar_id(self,calendar_err,calendar_id_null): '''清除错误日历id''' # 查询全部日历 res_info = self.get_calendarsList_info(calendar_id_null) print(res_info) # 循环取出所有日历id到数组中 for i in range(2): result = res_info['data']['calendar_list'][i]['calendar_id'] self.list.append(result) # 清除错误日历id self.list.remove(calendar_err) return self.list[0]
多端接口API写法:
from API.efs_Interface.base import Base from API.efs_Interface.order_api.ordersTestData import OrdersTestData as data class OrdersApiAddress(Base): """订单接口地址""" list = [] def create_orders(self): """承包商创建订单接口""" self.list.append(self.token) url = data.coUrl params = eval(str(data.coParams).replace('tokens', self.list[0])) r = self.send('POST', url, json=params).json() self.list.append(r['data']) print("list的值为:"+str(self.list)) print("==================创建订单结果:"+str(r)) return r def confirm_orders(self): """回收车确认订单接口""" orderId = self.list[1] url = data.cfoUrl params = str(data.cfoParams).replace('orderIds', orderId) params = eval(params.replace('tokens', self.token)) print(params) r = self.send('POST', url, params=params).json() print("list的值为:" + str(self.list)) print("==================确认订单结果:"+str(r)) return r def send_code(self): """承包商发送验证码接口""" url = data.scUrl params = eval(str(data.scParams).replace('tokens', self.list[0])) print(params) r = self.send('POST', url, params=params).json() self.list.append(r['data']) print("list的值为:" + str(self.list)) print("==================验证码结果:"+str(r)) return r def pay_orders(self): """承包商支付订单接口""" url = data.poUrl orderId = self.list[1] yzmxh = self.list[2] params = eval(str(data.poParams) .replace('orderIds', orderId) .replace('yzmxhs', yzmxh) .replace('tokens', self.list[0])) print(params) r = self.send('POST', url, params=params).json() print("==================支付订单结果:" + str(r)) return r if __name__ == '__main__': OrdersApiAddress(1).create_orders() OrdersApiAddress(2).confirm_orders() OrdersApiAddress(1).send_code() OrdersApiAddress(1).pay_orders()
2、test_case测试用例
分为三个部分:
①base用例:base_testcase.py
from API.feishu_work.calendar_api.feishuWorkAddress import FeishuWorkCalendars from API.test_case.calendar.baseCalendarsTestData import BaseCalendarsTestData class BaseTestCase: def setup_class(self): self.data = BaseCalendarsTestData() self.calendars = FeishuWorkCalendars() def setup(self): print("=======case_start=======") try: self.calendar_id = self.calendars.delete_error_calendar_id(self.data.calendar_err,self.data.calendar_id_null) except: pass def teardown(self): print("=======case_stop=======")
②用例数据:baseCalendarsTestData.py
from API.utils.functions import Functions class BaseCalendarsTestData(Functions): baseData = Functions().getYamlData('calendars') summary = baseData['summary'] newSummary = baseData['newSummary'] description = baseData['description'] permissions = baseData['permissions'] color = baseData['color'] summary_alias = baseData['summary_alias'] calendar_err = baseData['calendar_err'] calendar_id_null = baseData['calendar_id_null']
③测试用例:testCalendars.py
from API.test_case.base_testcase import BaseTestCase class TestCalendars(BaseTestCase): def test_create_calendars(self): res_create = self.calendars.create_calendars(self.data.summary, self.data.description, self.data.permissions, self.data.color, self.data.summary_alias) assert res_create['code'] == 0 result = self.calendars.get_calendarsList_info(self.calendars.delete_error_calendar_id(self.data.calendar_err,self.data.calendar_id_null)) assert result['code'] == 0 def test_get_calendars(self): res_get = self.calendars.get_calendarsList_info(self.data.calendar_id_null) print(res_get) assert res_get['code'] == 0 def test_update_calendars(self): res_update = self.calendars.update_calendars(self.calendar_id, self.data.newSummary, self.data.description, self.data.permissions, self.data.color, self.data.summary_alias) assert res_update['code'] == 0 res_get = self.calendars.get_calendarsList_info(self.data.calendar_id_null) print(res_get) assert res_get['code'] == 0 def test_delete_calendars(self): res_delete = self.calendars.delete_calendars(self.calendar_id) assert res_delete['code'] == 0 res_info = self.calendars.get_calendarsList_info(self.calendar_id) assert res_info['code'] == 0 print(res_info)
3、封装的公共方法utils
functions.py
import os import yaml class Functions: def upPath(self): '''获取上级目录路径''' basePath = os.path.dirname(os.path.dirname(__file__)) return basePath def getYamlData(self,yamlName='base'): '''获取yaml数据''' yamlPath = self.upPath() + f'/data/{yamlName}Data.yaml' with open(yamlPath,encoding='utf-8') as file: data = yaml.load(file) return data[yamlName]
4、yaml数据
baseData.yaml
base: calendarsUrl: "https://open.feishu.cn/open-apis/calendar/v4/calendars/" token: url: 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal/' params: app_id: 'cli_a18de0f937f9500d' app_secret: 'nUzgBNrv1sX20ARjI4dXUbVMYsDkUyPp'
八、举例目录结构
Github源码地址:https://github.com/Owen-ET/Mould_Automate_Code
不积跬步,无以致千里;不集小流,无以成江海。
如转载本文,请还多关注一下我的博客:https://www.cnblogs.com/Owen-ET/;
我的Github地址:https://github.com/Owen-ET————————————
无善无恶心之体, 有善有恶意之动, 知善知恶是良知, 为善去恶是格物。