Playwright与selenium都是基于WEB的GUI自动化测试的框架,前面我介绍了selenium的封装,这里来介绍基于Playwright的封装。
1.目录结构
首先仍旧先来介绍目录结构
____________________________________________________________
|______basepage 基础操作目录
|___________base.py 封装基本操作
|___________db.py 封装数据库操作
|___________page.py 封装Playwright page对象
|______data 测试数据目录
|___________data.yaml 数据
|___________data.py 封装对data.yaml数据的获取操作
|______pageobject 页面封装和业务封装目录
|___________flowobject.py 封装业务操作
|___________pageobject.py 封装页面操作
|______test 测试目录
|___________test.py 封装测试
- 基础操作(basepage)
basepage目录封装基础操作,包括base.py、db.py和page.py
2.1 base.py
base.py对Playwright专门做了调整,包括base、judge、WaitUtils和异常四个类。分别封装寻找元素、断言和等待方法。
2.1.1 base类
代码如下
class base:
@staticmethod
#通过label查找元素
def find_element_by_label(page,label_str):
return page.get_by_label(label_str)
@staticmethod
#通过text查找元素
def find_element_by_text(page,text_str):
return page.get_by_text(text_str)
@staticmethod
#通过location查找元素
def find_element_by_string(page,string):
return page.locator(string)
@staticmethod
#通过表达式查找元素
def find_element_by_xpath(page,xpath):
return page.locator("xpath="+xpath)
@staticmethod
#通过id查找元素
def find_element_by_id(page,id):
return page.locator("#"+id)
@staticmethod
#通过input/name查找元素
def find_element_by_input_name(page,name):
return page.locator("input[name="+name+"]")
@staticmethod
#通过type和value查找元素
def find_element_by_type_value(page,mytype,value):
return page.locator('input[type="'+mytype+'"][value="'+value+'"]')
@staticmethod
#通过name和value查找元素
def find_element_by_name_value(page,name,value):
return page.locator('input[name="'+name+'"][value="'+value+'"]')
@staticmethod
#通过name查找元素
def find_element_by_name(page,name):
return page.locator('input[name="'+name+'"]')
@staticmethod
#通过表达式查找元素
def find_element_by_classname(page,classname):
return page.locator(".="+classname)
@staticmethod
#通过role查找元素
def find_element_by_role(page,role,value):
return page.get_by_role(role,name=value)
@staticmethod
#通过placeholder查找元素
def find_element_by_placeholder(page,string):
return page.get_by_placeholder(string)
@staticmethod
#通过文本框值
def get_text_value(page,mytype):
return page.input_value('input[type='+mytype+']')
@staticmethod
#输入,每次输入都需要清除元素
def fill(element,str):
element.fill("")
element.fill(str)
@staticmethod
def save_cookies(page):
"""保存 Cookies 和 Local Storage 到文件"""
# 1. 保存 Cookies
cookies = page.context.cookies()
with open("cookies.pkl", "wb") as f:
pickle.dump(cookies, f)
# 2. 保存 Local Storage
localStorage = page.evaluate("() => JSON.stringify(window.localStorage)")
with open("localstorage.pkl", "wb") as f:
pickle.dump(localStorage, f)
@staticmethod
def load_cookies(page, url):
"""从文件恢复 Cookies 和 Local Storage"""
try:
# 1. 加载 Cookies
with open("cookies.pkl", "rb") as f:
cookies = pickle.load(f)
page.context.add_cookies(cookies)
# 2. 加载 Local Storage
with open("localstorage.pkl", "rb") as f:
localStorageStr = pickle.load(f)
script = f"""
(function(storage) {
{
try {
{
const entries = JSON.parse(storage);
for (const [key, value] of Object.entries(entries)) {
{
window.localStorage.setItem(key, value);
}}
}} catch(e) {
{
console.error('LocalStorage 恢复失败:', e);
}}
}})({
localStorageStr});
"""
page.evaluate(script)
# 3. 刷新页面使状态生效
page.goto(url)
page.reload()
page.goto("http://127.0.0.1:8000/goods_view/")
except Exception as e:
myexception.my_exception(page,f"状态恢复失败: {str(e)}","error_page.png")
@staticmethod
def execute_js_script(page,script):
return page.evaluate(script)
2.1.2 judge类
代码如下
class judge:
@staticmethod
#判断符合string格式(<td><a href="/update_address/\d/\d/">lable</a></td>)是否存在
def judge_link_in_td_exists(page,string,lable):
# 使用 CSS 选择器查找所有 <td> 下的 <a> 标签
elements = page.query_selector_all("td a")
found = False
for el in elements:
text = el.text_content().strip()
href = el.get_attribute("href")
if text == lable and re.match(string, href):
found = True
break
return found
@staticmethod
#通过xpath判断元素是否存在
def judge_by_xpath(page,string):
element = base.find_element_by_xpath(page,string)
assert element.count() > 0,"没有找到xpath="+string
@staticmethod
#通过页面是否含有text判断
def judge_by_text(page,field,text):
assert page.text_content(field) == text
@staticmethod
#通过页面是否部分含有text判断
def judge_by_part_text(page,field,text):
all_text = page.text_content(field)
if text in all_text:
assert 1 == 1
else:
assert 0 == 1
@staticmethod
#通过元素是否可见
def judge_element_is_visible(page,field):
element = page.locator(field)
is_visible = element.is_visible()
assert is_visible, field+"元素不可见"
#断言type的值为value
def judge_type_value(page,mytype,values):
i = 0
for value in(values):
expect(page.locator('input[type="'+mytype+'"]').nth(i)).to_have_value(value)
i+=1
2.1.3 WaitUtils类
代码如下
class WaitUtils:
@staticmethod
def wait_for_selector(page,sign,state="attached"):
page.wait_for_selector(sign, state=state)
2.1.4 异常类
代码如下
class myexception:
def my_exception(page,info,image):
print(info)
page.screenshot(path=image)
2.2 db.py
db.py封装对数据库的操作,对于selenium基本没有发生变化,用于tearDown清理数据库操作。
import pymysql
import sys
sys.path.append("../data")
from data import TestConfig
class ClassDB:
def connect_db(self):
host = 'localhost'
user = 'root'
password = '123456'
database = 'ebusiness'
return pymysql.connect(host=host, user=user, password=password, database=database, charset='utf8')
def init_db(self,conn):
config = TestConfig('default')
self.execute_query("DELETE FROM goods_order ORDER BY id DESC LIMIT 1",conn)
self.execute_query("DELETE FROM goods_orders ORDER BY id DESC LIMIT 1",conn)
self.execute_query("DELETE FROM goods_address where address='"+config.address+"'",conn)
self.execute_query("DELETE FROM goods_user where username='"+config.username+"'",conn)
def close_db(self,conn):
try:
conn.close()
except MySQLError as e:
print(f"数据库关闭失败: {e}")
def execute_query(self, query,conn,params=None):
with conn.cursor() as cursor:
cursor.execute(query, params)
conn.commit()
return cursor.fetchall()
def finsh_test(self):
connection=self.connect_db()
self.init_db(connection)
self.close_db(connection)
2.3 page.py
page.py作用类似于selenium中的driver.py
!/usr/bin/env python
#coding:utf-8
import sys
sys.path.append("../data")
from playwright.sync_api import sync_playwright
class mypages:
def __init__(self,config):
self.config = config
browser = self.config.browser
headless = self.config.headless
self.playwright = sync_playwright().start()
if browser.lower() == "chrome":
self.browser = self.playwright.chromium.launch(headless=headless)
if browser.lower() == "firfox":
self.browser = self.playwright.firefox.launch(headless=headless)
if browser.lower() == "edge":
self.browser = self.playwright.chromium.launch(headless=headless, channel="msedge")
self.page = self.browser.new_page()
headless的值取值与data目录中的daya.yaml中,表示是否已有头还是无头方式启动:headless=False表示有头,headless=True表示无头,无头方式运行要比有头速度快。
- 数据操作操作(data)
3.1 data.yaml
data.yaml基本没有变化,我仅为了优化程序,加了几个字段
environments:
default:
browser: "chrome" #以什么浏览器运行chrome、firfox、edge
url: "http://127.0.0.1:8000" #首页URL
headless: False #有头还是无头方式运行,headless=False表示有头,headless=True表示无头,无头方式运行要比有头速度快
username: "xixi" #用户名
password: "654321" #密码
repassword: "123456" #重置密码
email: "a@b.com" #Email
address: "首体南路1号" #配货地址
phone: "15434564455" #配货电话
number: "3" #选择商品数量
3.2 data.py
data.py对于data.yaml中的每个字段定义一个读取的方法。
import yaml
import os
class TestConfig:
def __init__(self, env='default'):
current_dir = os.path.dirname(os.path.abspath(__file__))
config_path = os.path.join(current_dir, 'data.yaml')
with open(config_path, 'r', encoding='utf-8') as f:
data = yaml.safe_load(f)
self.config = data['environments'][env]
@property
def browser(self):
return self.config['browser']
@property
def url(self):
return self.config['url']
@property
def headless(self):
return self.config['headless']
@property
def username(self):
return self.config['username']
@property
def password(self):
return self.config['password']
@property
def email(self):
return self.config['email']
@property
def address(self):
return self.config['address']
@property
def phone(self):
return self.config['phone']
@property
def repassword(self):
return self.config['repassword']
@property
def number(self):
return self.config['number']
- 页面和业务操作(pageobject)
4.1 pageobject.py
pageobject.py封装页面操作,在flowobject.py中采用xxx_page.xxx_action的操作形式。包括
login_page 登录页类
register_page 注册页类
goods_list_page 商品列表页类
goods_detail_page 商品详情页类
chart_page 购物车页类
order_page 订单页类
user_info_page 用户信息页类
add_address_page 添加收货地址页类
reset_password_page 重置密码页类
每个类包括元素定位,元素操作,动态等待和断言四类方法。由于某个操作后的定位往往在另外一个页类中,动态等待和断言往往结合成一个方法中,先动态等待,等到后再断言,这个方法定义在另一类中,在本类中调用。比如注册成功后需要在登录界面中断言(注册成功页面跳转到登录页面),在登录页面定义断言方法。
#登录类
class login_page:
#判断进入登录页面
def judge_enter_login_page(page):
judge_enter_login_page(page)是登录类中的一个验证方法,验证是否进入登录页面。在注册页类中
#注册类
class register_page:
#注册
def register(page,username,password,email):
…
#验证是否进入登录页面
login_page.judge_enter_login_page(page)
注册完毕验证是否进入登录页面。代码如下
#!/usr/bin/env python
#coding:utf-8
import sys,time
sys.path.append("../basepage")
from base import base,WaitUtils,judge
#登录类
class login_page:
#登录
def login(page,username,password):
username_field = base.find_element_by_label(page,"用户名:")
password_field = base.find_element_by_label(page,"密码:")
login_button = base.find_element_by_role(page,"button","登录")
base.fill(username_field,username)
base.fill(password_field,password)
login_button.click()
#判断进入商品列表页面
goods_list_page.judge_enter_goods_list_page(page,username)
#进入注册页面
def enter_register_page(page):
register_link=base.find_element_by_text(page,"注册")
register_link.click()
#判断进入注册页面
register_page.judge_enter_register_page(page)
#判断进入登录页面
def judge_enter_login_page(page):
WaitUtils.wait_for_selector(page,"#id_username")
judge.judge_by_text(page,'a[href="/register/"]',"注册")
#注册类
class register_page:
#注册
def register(page,username,password,email):
username_field= base.find_element_by_label(page,"用户名:")
password_field= base.find_element_by_label(page,"密码:")
email_field= base.find_element_by_label(page,"电子邮件:")
submit_field= base.find_element_by_role(page,"button","注册")
base.fill(username_field,username)
base.fill(password_field,password)
base.fill(email_field,email)
submit_field.click()
#验证是否进入登录页面
login_page.judge_enter_login_page(page)
#验证是否进入注册页面
def judge_enter_register_page(page):
WaitUtils.wait_for_selector(page,"#id_username")
judge.judge_by_text(page,'a[href="/index/"]',"登录")
#商品列表页面类
class goods_list_page:
#把商品放入购物车
def put_into_chart(page):
input_link = base.find_element_by_xpath(page,"/html/body/div/div[2]/div/table/tbody/tr[1]/td[5]/a")
input_link.click()
#验证把商品放入购物车成功
goods_list_page.judge_put_into_chart_success(page)
#查询商品
def serch_good(page,goods):
search_input = base.find_element_by_placeholder(page,"名称")
search_button = base.find_element_by_role(page,"button","搜索")
base.fill(search_input,goods)
search_button.click()
#验证查询商品成功
goods_list_page.judge_serch_good_success(page)
#进入查看商品详情页
def see_goods_detail(page):
goods_detail_link = base.find_element_by_xpath(page,"/html/body/div/div[2]/div/table/tbody/tr[1]/td[4]/a")
goods_detail_link.click()
#验证是否进入商品详情页成功
goods_detail_page.judge_enter_goods_detail_success(page)
#进入查看用户信息
def see_user_info(page,username):
user_link = base.find_element_by_text(page,username)
user_link.click()
#验证是否进入用户信息页成功
user_info_page.judge_enter_user_info_page_success(page)
#退出
def exit(page):
exit_link = base.find_element_by_text(page,"退出")
exit_link.click()
#验证是否进入登录页
login_page.judge_enter_login_page(page)
#进入购物车页面
def enter_chart(page):
enter_chart_link = base.find_element_by_text(page,"查看购物车")
enter_chart_link.click()
#验证是否进入购物车页面
chart_page.judge_enter_chart_page(page)
#查看所有订单
def view_all_orders(page):
view_all_orders_link = base.find_element_by_text(page,"查看所有订单")
view_all_orders_link.click()
#验证是否进入所有订单页
order_page.judge_enter_all_orders_page(page)
#验证是否进入商品列表页面
def judge_enter_goods_list_page(page,username):
WaitUtils.wait_for_selector(page,".navbar-form")
judge.judge_by_text(page,'a[href="/user_info/"]',username)
#验证把商品放入购物车成功
def judge_put_into_chart_success(page):
chart_sgin_xpath = "//font[@color='#FF0000' and text()='1']"
WaitUtils.wait_for_selector(page,chart_sgin_xpath)
judge.judge_by_part_text(page,'a[href="/view_chart/"]','查看购物车')
#验证查询商品成功
def judge_serch_good_success(page):
WaitUtils.wait_for_selector(page,".form-control")
judge.judge_by_text(page,'a[href="/view_goods/1/"]',"查看")
#购物车类
class chart_page:
#在购物车中更改商品数量
def change_goods_number(page,number):
number_field =base.find_element_by_id(page,"id_count")
change_button=base.find_element_by_type_value(page,"submit","修改")
base.fill(number_field,number)
change_button.click()
#验证修改后的购物车某个商品数量
chart_page.judge_number_in_chart(page,number)
#进入选择收货地址页,准备下单
def select_address(page):
pay_button = base.find_element_by_type_value(page,"submit","生成订单")
pay_button.click()
#验证是否进入选择收货地址页
order_page.judge_enter_select_address_page(page)
#验证是否进入购物车页面
def judge_enter_chart_page(page):
WaitUtils.wait_for_selector(page,".vIntegerField")
judge.judge_by_text(page,'a[href="/remove_chart/1/"]',"移除")
#验证修改后的购物车某个商品数量
def judge_number_in_chart(page,number):
get_number = base.get_text_value(page,"number")
assert get_number == number
#订单类
class order_page:
#选择收货地址
def select_address(page,address,phone):
found = judge.judge_link_in_td_exists(page,r"^/delete_address/\d+/\d+/$","删除")
if not found:
#生成订单
add_address_button=base.find_element_by_type_value(page,"submit","添加地址")
add_address_button.click()
#判断有无进入添加收货地址页
add_address_page.judge_enter_add_address(page)
#输入用户信息
add_address_page.enter_address_info(page,address,phone)
#判断是否生成收货地址
user_info_page.judge_having_address(page,"order")
#选择订单
address_field = base.find_element_by_input_name(page,"address")
next_button=base.find_element_by_type_value(page,"submit","下一步")
address_field.click()
next_button.click()
order_page.judge_in_order(page)
#验证这条订单是否生成
def judge_in_order(page):
WaitUtils.wait_for_selector(page,"td a:has-text('删除')")
judge.judge_by_text(page,"td a:has-text('删除')","删除")
#验证查看所有订单是否有这条订单
goods_list_page.view_all_orders(page)
#验证是否进入选择收货地址页
def judge_enter_select_address_page(page):
WaitUtils.wait_for_selector(page,".col-md-6")
judge.judge_element_is_visible(page,"form[method='POST']")
#验证是否进入所有订单页
def judge_enter_all_orders_page(page):
WaitUtils.wait_for_selector(page,"td a:has-text('删除')")
judge.judge_by_text(page,"td a:has-text('删除')","删除")
#用户信息类
class user_info_page:
#从用户信息页面进入添加用户地址页面
def enter_add_adress(page):
add_address_button=base.find_element_by_role(page,"button","添加地址")
add_address_button.click()
#验证是否进入添加用户地址页面
add_address_page.judge_enter_add_address(page)
#从用户信息页面进入修改密码
def reset_password(page):
enter_reset_password_button = base.find_element_by_type_value(page,"submit","修改密码")
enter_reset_password_button.click()
#判断是否进入重置密码页面
reset_password_page.judge_enter_reset_password_page(page)
#查看进入用户信息页成功
def judge_enter_user_info_page_success(page):
WaitUtils.wait_for_selector(page,"#add_address")
mystr=["修改密码","添加地址"]
judge.judge_type_value(page,"submit",mystr)
#判断判断是否生成收货地址
def judge_having_address(page,sign):
if sign=="order":
judge.judge_element_is_visible(page,"input[type='radio']")
elif sign=="address":
found = judge.judge_link_in_td_exists(page,r"^/update_address/\d+/\d+/$","修改")
assert found, "未找到符合条件的 '"+lable+"' 链接"
else:
print("sign in fuction user_info_page.judge_having_address(page,sign) is error")
#添加收货地址类
class add_address_page:
#输入用户地址信息
def enter_address_info(page,address,phone):
address_field=base.find_element_by_name(page,"address")
phone_field=base.find_element_by_name(page,"phone")
submit_button=base.find_element_by_role(page,"button","提交")
base.fill(address_field,address)
base.fill(phone_field,phone)
submit_button.click()
#判断有无用户地址信息
user_info_page.judge_having_address(page,"address")
#判断有无进入添加收货地址页
def judge_enter_add_address(page):
WaitUtils.wait_for_selector(page,"#id_address")
judge.judge_by_text(page,'button',"提交")
#商品详情类
class goods_detail_page:
#查看进入商品详情页成功
def judge_enter_goods_detail_success(page):
WaitUtils.wait_for_selector(page,".input-group")
judge.judge_by_text(page,'a[href="/add_chart/1/2/"]',"放入购物车")
#重置密码类
class reset_password_page:
#重置密码
def reset_password(page,password,repassword):
old_password_field=base.find_element_by_name(page,"oldpassword")
new_password_field=base.find_element_by_name(page,"newpassword")
renew_password_field=base.find_element_by_name(page,"checkpassword")
submit_button=base.find_element_by_type_value(page,"submit","修改")
base.fill(old_password_field,password)
base.fill(new_password_field,repassword)
base.fill(renew_password_field,repassword)
submit_button.click()
#重置密码成功
reset_password_page.reset_password_success(page)
#重置密码成功
def reset_password_success(page):
judge.judge_by_text(page,'p[style="color:red"]',"密码修改成功")
#判断是否进入重置密码页面
def judge_enter_reset_password_page(page):
WaitUtils.wait_for_selector(page,'input[name="oldpassword"]')
value = ["修改"]
judge.judge_type_value(page,"submit",value)
4.2 flowobject.py
flowobject.py封装业务流操作test.py,在test/test.py中采用xxx_flow.xxx_business的操作形式。在这里定义了如下几个类。
1)userFlow: 用户流
Register_and_Login(self) 注册然后登录
reset_password(self) 重置密码
2)goodsFlow: 商品流
search_goods(self,goods) 查询商品
put_goods_into_chart(self) 放入购物车
see_goods_detail(self) 查看商品详情
3)addressFlow: 收货地址流
- add_address(self) 添加收货地址
4)orderFlow: 订单流
- pay_order(self) 下单
代码如下
#!/usr/bin/env python
#coding:utf-8
import sys
sys.path.append("../basepage")
from pageobject import *
from base import myexception
class userFlow:
def __init__(self, config, page):
self.config = config
self.page = page
#注册然后登录
def Register_and_Login(self):
try:
self.page.goto(self.config.url)
#进入注册页
login_page.enter_register_page(self.page)
except Exception as e:
myexception.my_exception(self.page,f"进入注册页失败: {str(e)}","enter_register_page_fail.png")
try:
#注册用户
register_page.register(self.page,self.config.username, self.config.password, self.config.email)
except Exception as e:
myexception.my_exception(self.page,f"注册失败: {str(e)}","register_fail.png")
try:
#用注册用户登录
login_page.login(self.page,self.config.username, self.config.password)
except Exception as e:
myexception.my_exception(self.page,f"登录失败: {str(e)}","login_fail.png")
#重置密码
def reset_password(self):
try:
#进入查看用户信息
goods_list_page.see_user_info(self.page,self.config.username)
except Exception as e:
myexception.my_exception(self.page,f"进入用户详情页失败: {str(e)}","enter_user_info_page_fail.png")
try:
#从用户信息页面进入修改密码
user_info_page.reset_password(self.page)
except Exception as e:
myexception.my_exception(self.page,f"进入修改页密码失败: {str(e)}","enter_reset_password_page_fail.png")
#判断是否进入重置密码页面
try:
#重置密码
reset_password_page.reset_password(self.page,self.config.password,self.config.repassword)
except Exception as e:
myexception.my_exception(self.page,f"重置密码失败: {str(e)}","reset_password_fail.png")
try:
#退出系统
goods_list_page.exit(self.page)
except Exception as e:
myexception.my_exception(self.page,f"退出系统失败: {str(e)}","exit_fail.png")
try:
#用重置密码登录
login_page.login(self.page,self.config.username,self.config.repassword)
except Exception as e:
myexception.my_exception(self.page,f"用重置密码登录失败: {str(e)}","login_using_new_password_fail.png")
class goodsFlow:
def __init__(self, config, page):
self.config = config
self.page = page
#查询商品
def search_goods(self,goods):
try:
#查询商品
goods_list_page.serch_good(self.page,goods)
except Exception as e:
myexception.my_exception(self.page,f"搜索失败: {str(e)}","search_goods_failed.png")
#放入购物车
def put_goods_into_chart(self):
try:
#把商品放入购物车
goods_list_page.put_into_chart(self.page)
except Exception as e:
myexception.my_exception(self.page,f"放入购物车失败: {str(e)}","put_into_char_failed.png")
#查看商品详情
def see_goods_detail(self):
try:
#进入查看商品详情
goods_list_page.see_goods_detail(self.page)
except Exception as e:
myexception.my_exception(self.page,f"查看商品详情失败: {str(e)}","see_goods_detail_failed.png")
class addressFlow:
def __init__(self, config, page):
self.config = config
self.page = page
#添加收货地址
def add_address(self):
try:
#进入查看用户信息
goods_list_page.see_user_info(self.page,self.config.username)
except Exception as e:
myexception.my_exception(self.page,f"进入用户详情页失败: {str(e)}","see_user_info_fail.png")
try:
#从用户信息页面进入添加用户地址页面
user_info_page.enter_add_adress(self.page)
except Exception as e:
myexception.my_exception(self.page,f"进入添加地址页失败: {str(e)}","enter_add_address_fail.png")
try:
#输入用户地址信息
add_address_page.enter_address_info(self.page,self.config.address,self.config.phone)
except Exception as e:
myexception.my_exception(self.page,f"进入添加地址页失败: {str(e)}","enter_add_address_fail.png")
class orderFlow:
def __init__(self, config, page):
self.config = config
self.page = page
#下单
def pay_order(self):
try:
#把商品放入购物车
goods_list_page.put_into_chart(self.page)
except Exception as e:
myexception.my_exception(self.page,f"放入购物车失败: {str(e)}","put_into_char_failed.png")
try:
#进入购物车
goods_list_page.enter_chart(self.page)
except Exception as e:
myexception.my_exception(self.page,f"进入购物车失败: {str(e)}","enter_chart_fail.png")
try:
#在购物车总更改商品数量
chart_page.change_goods_number(self.page,self.config.number)
except Exception as e:
myexception.my_exception(self.page,f"修改商品数量失败: {str(e)}","change_number_fail.png")
try:
#进入选择收货地址页,准备下单
chart_page.select_address(self.page)
except Exception as e:
myexception.my_exception(self.page,f"选择收货地址页,准备下单失败: {str(e)}","prepare_pay_order_fail.png")
try:
#选择收货地址
order_page.select_address(self.page,self.config.address,self.config.phone)
except Exception as e:
myexception.my_exception(self.page,f"选择收货地址失败: {str(e)}","select_address_fail.png")
- 测试操作(test)
test目录下为测试代码
#!/usr/bin/env python
#coding:utf-8
import sys
sys.path.append("../data")
sys.path.append("../basepage")
sys.path.append("../pageobject")
import unittest
from page import mypages
from base import base
from db import ClassDB
from data import TestConfig
from flowobject import *
class CheckEbusiness(unittest.TestCase):
def setUp(self):
self.config = TestConfig('default')
page = mypages(self.config)
self.page = page.page
self.browser = page.browser
self.playwright = page.playwright
self.userFlow = userFlow(self.config,self.page)
self.goodsFlow = goodsFlow(self.config,self.page)
self.addressFlow = addressFlow(self.config,self.page)
self.orderFlow = orderFlow(self.config,self.page)
# 测试注册和登录
def test_Register_Login(self):
self.userFlow.Register_and_Login()
base.save_cookies(self.page)
#测试查询商品
def test_search(self):
base.load_cookies(self.page,self.config.url)
self.goodsFlow.search_goods("茶")
#测试放入购物车
def test_put_into_chart(self):
base.load_cookies(self.page,self.config.url)
self.goodsFlow.put_goods_into_chart()
#测试查看商品详情
def test_see_goods_detail(self):
base.load_cookies(self.page,self.config.url)
self.goodsFlow.see_goods_detail()
#测试修改密码
def test_reset_password(self):
base.load_cookies(self.page,self.config.url)
self.userFlow.reset_password()
#测试新加地址
def test_add_address(self):
base.load_cookies(self.page,self.config.url)
self.addressFlow.add_address()
#测试下单
def test_pay_order(self):
base.load_cookies(self.page,self.config.url)
self.orderFlow.pay_order()
def tearDown(self):
self.browser.close()
self.playwright.stop()
@classmethod
def tearDownClass(cls):
try:
db = ClassDB()
db.finsh_test()
except:
pass
if __name__ == '__main__':
suite=unittest.TestSuite()
suite.addTest(CheckEbusiness("test_Register_Login"))
suite.addTest(CheckEbusiness("test_search"))
suite.addTest(CheckEbusiness("test_put_into_chart"))
suite.addTest(CheckEbusiness("test_see_goods_detail"))
suite.addTest(CheckEbusiness("test_add_address"))
suite.addTest(CheckEbusiness("test_reset_password"))
suite.addTest(CheckEbusiness("test_pay_order"))
runner=unittest.TextTestRunner()
runner.run(suite)
- 比较
最后让我们比较一下selenium、playwright有头模式和无头模式运行电子商务产品7个用例的时间。
由此可见从运行速度而言playwright远远都快于selenium、无头模式快于有头模式。
顾翔凡言:人工智能未来的发展瓶颈在于对知识的更新。唯一不变的是变化,知识发生了变化,人工智能软件能否及时跟进变化,可能阻碍人工智能的使用。