【自总结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

 

posted @ 2021-12-31 11:28  Owen_ET  阅读(620)  评论(0编辑  收藏  举报