招聘网站套餐费用怎么做分录百度一下知道首页
一:简化
1. 新建common 包 新建diver.py
封装浏览器驱动类
from selenium import webdriverclass Driver():"""浏览器驱动类定义 一个【获取浏览器驱动对象driver的方法】。支持多种类型浏览器"""def get_driver(self,browser_type):if browser_type == 'chrome':self.driver = webdriver.Chrome()elif browser_type == 'Firefox':self.driver = webdriver.Firefox()# 最大化窗口、隐式等待、最大加载时长self.driver.maximize_window()self.driver.implicitly_wait(20)self.driver.set_page_load_timeout(20) # 页面加载时长, 超时则停止,避免因页面加载过慢而拖延整个测试流程return self.driver
新建configs包,config.py
把超时时间,隐式等待时间写到配置里
两种写配置的方式,都行
# 页面允许超时时间 小技巧 按 ctrl +shift +U, 可以转大写
SET_PAGE_LOAD_TIMEOUT = 20# 默认浏览器类型
DEF_BROWSER_TYPE = 'chrome'
我用第二种方式,那么在driver.py 中,就这么导入
from configs.config import SET_PAGE_LOAD_TIMEOUT,DEF_BROWSER_TYPE
driver.py 中,引入config的配置的时间,引用config中配置的浏览器类型
from selenium import webdriver
from configs.config import SET_PAGE_LOAD_TIMEOUT,DEF_BROWSER_TYPE
class Driver():"""浏览器驱动类定义 一个【获取浏览器驱动对象driver的方法】。支持多种类型浏览器"""def get_driver(self,browser_type = DEF_BROWSER_TYPE):if browser_type == 'chrome':self.driver = webdriver.Chrome()elif browser_type == 'Firefox':self.driver = webdriver.Firefox()# 最大化窗口、隐式等待、最大加载时长self.driver.maximize_window()self.driver.implicitly_wait(20)self.driver.set_page_load_timeout(SET_PAGE_LOAD_TIMEOUT) # 页面加载时长, 超时则停止,避免因页面加载过慢而拖延整个测试流程return self.driver
2. 新建页面基类
在common包中,新建basePage.py , BasePage类,
表示页面基类, 把不同的页面,能做的同样的事情,都封装在这个类中。
new_Driver() 方法,返回的是driver,页面类示例对象就可以用到
back() ,表示二次封装的回退方法
get_element(), 表示定位方法
input_text ,表示文本框的输入方法
暂时先写这么多,还可以封装点击, 等等方法
from common.driver import Driverclass BasePage:"""页面基类:不同的页面 能做同样的事,封装在这个类中打开浏览器、进入页面、定位元素、点击、输入等"""def __init__(self):self.driver = Driver().get_driver() # 这个就表示打开浏览器# 打开网址def open_url(self,url): # 二次封装,提供更多的可能性self.driver.get(url)# 定位到元素def get_element(self,locator):""":param locator: 如: 'id','kw':return:"""return self.driver.find_element(*locator)# 输入文本def input_text(self,locator,text,append=False):# 默认:清空后输入if not append:self.get_element(locator).clear()self.get_element(locator).send_keys(text)# 否则是追加输入else:self.get_element(locator).send_keys(text)# 返回driver对象, 让页面对象灵活操作def new_Driver(self):return self.driver# 倒退def back(self):self.driver.back()
3.新建pages包
一个页面一个py文件, 在pages目录下,
新增baidu_page.py
表示 百度的页面,里面
有纯元素,比如下面的 “【百度一下】 按钮元素”
有元素做动作的方法,“输入框输入文本”
在main中,可以进行调试
from common.basePage import BasePage# 继承基类
class BaiduPage(BasePage):def open_baidu_page(self):# self.open_url(f"{URL}/login")self.open_url("https://www.baidu.com/")return self # 返回后,可以链式调用 BaiduPage().open_baidu_page().login_polly('花西子262','123456')# (动作)输入框输入xxdef input_ele_input(self,text):self.input_text(('id','kw'),text)# (元素) 百度一下 按钮def submit_ele(self):return self.get_element(('id','su'))Baidu_Page_Obj = BaiduPage()if __name__ == '__main__':Baidu_Page_Obj = BaiduPage()# 输入Baidu_Page_Obj.open_baidu_page().input_ele_input("测试一下")# 点击确定Baidu_Page_Obj.submit_ele().click()
新建sahitest_page.py
再新增一个页面,其中,封装了两个元素
main 中
- 点击一个元素,然后 使用 basePage中封装的 back方法,回退
- 再点击另一个元素,使用basePage中,先获取到driver,然后再用driver
import time
from common.basePage import BasePage
# 继承基类
class SahiTestPage(BasePage):def open_sahi_page(self):self.open_url("https://sahitest.com/demo/")return self# (元素1)def _ele1(self):return self.get_element(("link text",'Drag Drop Test'))# (元素2)def _ele2(self):return self.get_element(("link text",'Alert Test'))sihi_Page_Obj = SahiTestPage()if __name__ == '__main__':sihi_Page_Obj = SahiTestPage()# 打开网址sihi_Page_Obj= sihi_Page_Obj.open_sahi_page()# 点击一个元素sihi_Page_Obj._ele2().click()time.sleep(2)# 回退 (使用封装的back方法)sihi_Page_Obj.back()# 点击第二个元素sihi_Page_Obj._ele1().click()time.sleep(2)# 回退(使用dirver对象 的)sihi_Page_Obj.new_Driver().back()
4 . 新建testCases包。
新建test_demo1.py
一个py文件就用来写一个 页面的测试用例,可以这么设计,那这个就写百度页面的测试用例。
我就直接两个用例,对应两个页面了
- 用例1: 百度页面 输入 CSDN,百度一下
- 用例2: sahitest页面,点击一个, 回退,点击另一个,再回退
from pages.baidu_page import Baidu_Page_Obj
from pages.sahitest_page import sihi_Page_Obj
import time,pytestclass Test_Demo():def test_case1(self):"""打开百度"""Baidu_Page_Obj.open_baidu_page().input_ele_input("CSDN")Baidu_Page_Obj.submit_ele().click()time.sleep(1)def test_case2(self):"""打开sihitest网页"""time.sleep(1)sihi_Page_Obj.open_sahi_page()# 点击一个元素sihi_Page_Obj._ele2().click()time.sleep(2)# 回退 (使用封装的back方法)sihi_Page_Obj.back()# 点击第二个元素sihi_Page_Obj._ele1().click()time.sleep(2)# 回退(使用dirver对象 的)sihi_Page_Obj.new_Driver().back()if __name__ == '__main__':pytest.main([__file__])
pytest的知识,要执行main中的代码要设置pycharm:不明白可以看 【自动化总结1】pytest使用整理
执行时,会完成测试用例 ,但是会打开两个浏览器。这个是可以去解决的问题
二:升级(待整理)
集中管理元素定位、解决打开多个浏览器问题(如果只打开一次,就只登录一次就够了) 、
补充basePage,基类中的方法
driver.py中,代码补充。get_element 查找元素,用显示等待的方式来查
# 定位到元素def get_element(self,locator):""":param locator: 如: 'id','kw':return:"""# return self.driver.find_element(*locator)# 改用下面的显示等待的定位return WebDriverWait(driver=self.driver, timeout=10, poll_frequency=0.5).until(EC.visibility_of_element_located(locator))
和 get_elements 获取元素列表
def get_elements(self, locator):# ------------这段代码生效否,有待考究----------------------WebDriverWait(# 传入浏览器对象driver=self.driver,# 传入超时时间#timeout=TIMEOUT, # 可以写到配置里timeout=10,# 传入轮询时间 # poll_frequency=POLL_FREQUENCY).until( # 也可以写到配置里poll_frequency=0.5).until(EC.visibility_of_element_located(locator))# ------------这段代码生效否,有待考究----------------------# 返回元素列表return self.driver.find_elements(*locator)
再添加一个点击元素的方法。和获取元素文本的方法
# 点击元素def click_element(self,locator):self.get_element(locator).click()# 获取元素文本信息(用来断言)def get_element_text(self, locator):# 获取元素文本(查找元素时,已经做了等待)return self.get_element(locator).textdef get_elements_text(self,locator):#遍历得到每个元素的textreturn [ele.text for ele in self.get_elements(locator)]
封装使用 元素定位器的yml文件
pages中写 login_page.py ,定位器写死
来写一次登录页,首先先把元素定位器写死
from selenium.webdriver.common.by import By
from common.basePage import BasePage
from configs.config import HOSTclass LoginPage(BasePage):# 打开登录页面def open_loginpage(self):self.open_url(f"{HOST}/#/login")# def login_polly(self, username, password):# # 定位器是通过基类定义的方法获取的# # self.input_text([By.ID, 'username'], username)# time.sleep(0.5)# self.input_text(self.username_input, username)# time.sleep(0.5)# self.input_text(self.password_input, password)# time.sleep(0.5)# self.click_element(self.login_button)def login_polly(self, username, password):# 定位器是通过基类定义的方法获取的self.input_text([By.ID, 'username'], username)self.input_text(['id', 'password'], password)self.click_element(["id", "btnLogin"])if __name__ == '__main__':lp = LoginPage()lp.open_loginpage()lp.login_polly("hello","world")
管理定位器方式1(推荐这种吧,丑虽然丑了点):
新建 allelements.py 文件中。
按如下的方式,就是所有的页面的元素都写在一个类中。
然后 login_page.py 中, 去读取配置。
管理定位器方式2 :使用yml文件(有弊端)
目标是在页面基类中的init方法中,就直接能获取各自页面的定位器。
1.在configs中,新建 allelements.yml
其中: LoginPage就表示 登录页, MainPage表示首页。 后续在定义页面类时,就要写同样的类名
LoginPage: # 登录页面 这个key要和 class页面类名一致username_input : ["id", username] # 用户输入框 会默认成字符串password_input: ["id", "password"] # 密码输入框login_button: ["id", "btnLogin"] # 登录按钮message_text: [ 'css selector','.el-message--error' ] #登录错误消息文本message_text_less: [ 'css selector','.el-form-item__error' ] #密码不能小于3位MainPage: #首页home_button: [ 'xpath','//*[text()="首页"]' ] #首页按钮logout_button: [ 'xpath',"//span[text()='退出']" ] #退出按钮personal_button: [ 'xpath','//img' ] #个人中心按钮menu_productmanage: [ 'xpath',"//span[text()='商品管理']" ]submenu_pm_productlist: [ 'xpath',"//span[text()='商品列表']" ]submenu_pm_addproduct: [ 'xpath',"//span[text()='添加商品']" ]submenu_pm_productkind: [ 'xpath',"//span[text()='商品分类']" ]submenu_pm_producttype: [ 'xpath',"//span[text()='商品类型']" ]submenu_pm_brandmanage: [ 'xpath',"//span[text()='品牌管理']" ]submenu_pm_productattr: [ 'xpath',"//span[text()='商品规格']" ]submenu_pm_productgift: [ 'xpath',"//span[text()='赠礼列表']" ]submenu_pm_productconsult: [ 'xpath',"//span[text()='商品评论']" ]menu_ordermanage: [ 'xpath',"//span[text()='订单管理']" ]menu_membermanage: [ 'xpath',"//span[text()='会员管理']" ]today_orders: [ 'css selector','.el-row > div:nth-child(1) .total-value' ] #今日下单数today_sales: [ 'css selector','.el-row > div:nth-child(2) .total-value' ] #今日销售总额today_product: [ 'css selector','.el-row > div:nth-child(3) .total-value' ] #今日商品数today_members: [ 'css selector','.el-row > div:nth-child(4) .total-value' ] #今日会员
2. 新建utils包,新建 handle_path.py
有了它,路径大概率不会出错。
f'{config_path}/allelements.yml' 这样就表示定位器的路径
import os
"""
需求: 代码在任意路径都可以获取到项目工程的绝对路径
""""""工程路径"""
project_path = os.path.dirname( os.path.dirname(os.path.abspath(__file__)))"""配置路径"""
config_path = os.path.join(project_path,'configs')"""测试数据路径"""
# case_data_path = os.path.join(project_path,'datas')
# logs_path = os.path.join(project_path,'outFiles\logs')
# screenshots_path = os.path.join(project_path,'outFiles\screenshots')
# reports_path = os.path.join(project_path,'outFiles\\reports')common_path = os.path.join(project_path,'common')testcase_path = os.path.join(project_path,'testCases')if __name__ == '__main__':print(common_path)
3. 在utils包中,新建 handle_yml.py
里面写一个获取yml文件的方法。 获取出来得到 字典的形式, 长下面这个样子
4. 在basePage.py 中, 更新init方法。
from utils.handle_path import config_path
from utils.handle_yml import get_yaml_dataclass BasePage:"""页面基类:不同的页面 能做同样的事,封装在这个类中打开浏览器、进入页面、定位元素、点击、输入等"""def __init__(self):self.driver = Driver().get_driver() # 这个就表示打开浏览器"""1.读取yml配置文件中各个页面的定位器- 哪个页面类继承basepage,就能得到哪个页面的定位器- 通过 self.__class__.__name__ 获取当前类名"""self.locators = get_yaml_data(f'{config_path}/allelements.yml')[self.__class__.__name__]# 设置 实例 element_name 属性 的值是locator ----有利于代码编写for element_name, locator in self.locators.items():setattr(self, element_name, locator)
解析:其中:self.locators 就是一个字典。 把 键和值获取出来。
再用 setattr 设置成属性对。
4.使用定位器
首先类名要LoginPage和 yml文件中的是一致的、这样也可以运行, 这么做的好处时,页面元素好管理,代码也好读。
5.yml的弊端
待补充
用例中,进行断言
testcases包中,新建test_login_success.py , 从这个文件命名中,可以看出,登录成功的用例会写到这里,登录失败的会写到其他地方。
但我一般,不会反复进行登录,我只会写一个登录成功的用例,执行后,后续就不会执行它了
这里主要介绍下如何断言。新建 test_login.py
利用。basePage 中定义的获取文本信息来进行断言、 或者获取页面标题,来进行断言
如登录成功后,获取页面标题,判断标题是不是“首页”
from pages.login_page import LoginPage
import pytestclass Test_Demo():def test_case1(self):loginobj =LoginPage()loginobj.open_loginpage()loginobj.login_polly("朝天宫002",123456)"""方式1: 获取标题来进行断言"""# assert loginobj.new_Driver().title == "首页"print("-----------------------------",loginobj.new_Driver().title) # 标题打印出来是“保利商城”"""方式1: 获取标题来进行断言"""print("++++++++++++++++++++++++++++",loginobj.get_element_text(['xpath','//*[text()="首页"]']))assert loginobj.get_element_text(['xpath','//*[text()="首页"]']) == "首页"if __name__ == '__main__':pytest.main([__file__,'-s'])