首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >基于Playwright的测试代码架构设计

基于Playwright的测试代码架构设计

原创
作者头像
顾翔
发布2025-12-10 12:39:32
发布2025-12-10 12:39:32
730
举报

Playwright与Selenium都是基于Web GUI自动化测试的框架,这里来介绍基于Playwright的封装的架构设计。

1 目录结构

首先仍旧先来介绍目录结构,见表1所示。

表1 Playwright语句的封装目录结构

目录

文件

含义

basepage

基础操作目录

base.py

封装基本操作

db.py

封装数据库操作

page.py

封装Playwright的page对象

data

测试数据目录

data.yaml

数据yaml文件

data.py

封装对data.yaml数据的获取操作

pageobject

页面封装和业务封装目录

flowobject.py

封装业务操作

pageobject.py

封装页面操作

test

测试目录

test.py

封装测试

2 基础操作(basepage)

basepage目录封装基础操作,包括base.py、db.py和page.py

1)base.py

base.py对Playwright专门做了调整,包括base、judge、WaitUtils和myexception四个类。分别封装定位操作元素、断言、等待和异常方法。

(1)base类

函数说明

PlayWright的定位操作方法比Selenium丰富,但常用的也不多,对常用的定位操作方法进行封装,包括下面几个方法。

•find_element_by_label(page,label_str):通过label查找元素。

•find_element_by_text(page,text_str):通过text查找元素。

•find_element_by_string(page,string):通过location查找元素。

•find_element_by_xpath(page,xpath):通过xpath表达式查找元素。

•find_element_by_id(page,id):通过id查找元素。

•find_element_by_input_name(page,name):通过input/name查找元素。

•find_element_by_type_value(page,mytype,value):通过type和value查找元素。

•find_element_by_name_value(page,name,value):通过name和value查找元素。

•find_element_by_name(page,name):通过name查找元素。

•find_element_by_classname(page,classname):通过classname查找元素。

•find_element_by_role(page,role,value):通过role查找元素。

•find_element_by_placeholder(page,string):通过placeholder查找元素。

•get_text_value(page,mytype):获得input值。

•fill(element,str):输入,每次输入都需要清除元素。

•save_cookies(page):保存Cookies和Local Storage到文件。

•load_cookies(page,url):从文件恢复Cookies和Local Storage。

•execute_js_script(page,script):执行JavaScript语句。

测试代码

代码如下。

base.py

代码语言:txt
复制
import pickle,re
from playwright.sync_api import expect
class base:
  @staticmethod
  def find_element_by_label(page,label_str):
   """通过label查找元素"""
   return page.get_by_label(label_str)
  @staticmethod
  def find_element_by_text(page,text_str):
   """通过text查找元素"""
   return page.get_by_text(text_str)
  @staticmethod
  def find_element_by_string(page,string):
   """通过location查找元素"""
   return page.locator(string)
  @staticmethod
  def find_element_by_xpath(page,xpath):
   """通过表达式查找元素"""
   return page.locator("xpath="+xpath)
  @staticmethod
  def find_element_by_id(page,id):
   """通过id查找元素"""
   return page.locator("#"+id)
  @staticmethod
  def find_element_by_input_name(page,name):
   """通过input/name查找元素"""
   return page.locator("input[name="+name+"]")
  @staticmethod
  def find_element_by_type_value(page,mytype,value):
   """通过type和value查找元素"""
   return page.locator('input[type="'+mytype+'"][value="'+value+'"]')
  @staticmethod
  def find_element_by_name_value(page,name,value):
   """通过name和value查找元素"""
   return page.locator('input[name="'+name+'"][value="'+value+'"]')
  @staticmethod
  def find_element_by_name(page,name):
   """通过name查找元素"""
   return page.locator('input[name="'+name+'"]')
  @staticmethod
  def find_element_by_classname(page,classname):
   """通过classname查找元素"""
   return page.locator(".="+classname)
  @staticmethod
  def find_element_by_role(page,role,value):
   """通过role查找元素"""
   return page.get_by_role(role,name=value)
  @staticmethod
  def find_element_by_placeholder(page,string):
   """通过placeholder查找元素"""
   return page.get_by_placeholder(string)
  @staticmethod
  def get_text_value(page,mytype):
   """获得input值"""
   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 到文件"""
   cookies=page.context.cookies()#1. 保存 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:
   with open("cookies.pkl","rb") as f: #1. 加载 Cookies
   cookies=pickle.load(f)
   page.context.add_cookies(cookies)
   with open("localstorage.pkl","rb") as f: #2. 加载 Local Storage
   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)
   page.goto(url) #3. 刷新页面使状态生效
   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):
   """执行JavaScript程序"""
   return page.evaluate(script)

(2)judge类

函数说明

•judge_link_in_td_exists(page,string,lable):使用CSS选择器查找所有<td>下的<a>标签。

•judge_by_xpath(page,string):通过xpath判断元素是否存在。

•judge_by_text(page,field,text):通过页面是否含有text判断。

•judge_by_part_text(page,field,text):通过页面是否部分含有text判断。

•judge_element_is_visible(page,field):通过元素是否可见。

•judge_type_value(page,mytype,values):断言type的值为values。

测试代码

base.py

代码语言:txt
复制
class judge:
  @staticmethod
  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
  def judge_by_xpath(page,string):
   """通过xpath判断元素是否存在"""
   element=base.find_element_by_xpath(page,string)
   assert element.count()>0,"没有找到xpath="+string
  @staticmethod
  def judge_by_text(page,field,text):
   """通过页面是否含有text判断"""
   assert page.text_content(field)==text
  @staticmethod
  def judge_by_part_text(page,field,text):
  """通过页面是否部分含有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+"元素不可见"
  @staticmethod
  def judge_type_value(page,mytype,values):
  """断言type的值为value"""
  i=0
  for value in(values):
   expect(page.locator('input[type="'+mytype+'"]').nth(i)).to_have_value(value)
   i+=1

(3)WaitUtils类

base.py

代码语言:txt
复制
class WaitUtils:
  @staticmethod
  def wait_for_selector(page,sign,state="attached"):
   """等待元素状态(默认attached)"""
   page.wait_for_selector(sign,state=state)

(4)异常类

base.py

代码语言:txt
复制
class myexception:
  def my_exception(page,info,image):
   print(info)
   page.screenshot(path=image)

2)db.py

db.py封装对数据库的操作,对于selenium基本没有发生变化,用于tearDown()清理数据库操作。

(1)db.py

代码语言:txt
复制
import pymysql
import sys
sys.path.append("../data")
from data import Config
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 close_db(self,conn):
   """关闭数据库"""
   try:
   conn.close()
   except MySQLError as e:
   print(f"数据库关闭失败:{e}")
  def init_db(self,conn):
   """测试初始化"""
   config=Config('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 execute_query(self,query,conn,params=None):
   """执行SQL语句"""
  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)

3)page.py

page.py作用类似于selenium中的driver.py。

(1)page.py

代码语言:txt
复制
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()=="firefox":
  self.browser=self.playwright.firefox.launch(headless=headless)
 if browser.lower()=="webkit":
  self.browser=self.playwright.WebKit.launch(headless=headless)
 if browser.lower()=="edge":
  self.browser=self.playwright.chromium.launch(channel="msedge")
 self.page=self.browser.new_page()
headless的值取值与data目录中的data.yaml中,表示是否已有头还是无头方式启动:headless=False表示有头,headless=True表示无头。

3 数据操作操作(data)

1)data.yaml

(1)data.yaml

代码语言:txt
复制
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"#选择商品数量

(2)data.py

data.py对于data.yaml中的每个字段定义一个读取的方法。

data.py

代码语言:txt
复制
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']

4 页面和业务操作(pageobject)

1)pageobject.py

类及函数说明

pageobject.py封装页面操作,在flowobject.py中采用XXXPage.XXXAction()的操作形式。包括。

•class login_page:登录类。

  • login(page,username,password):登录。
  • enter_register_page(page):进入注册页面。
  • judge_enter_login_page(page):判断进入登录页面。

•class register_page:注册类。

  • register(page,username,password,email):注册。
  • judge_enter_register_page(page):验证是否进入注册页面。

•class goods_list_page:商品列表页类。

  • put_into_chart(page):把商品放入购物车。
  • serch_good(page,goods):查询商品。
  • see_goods_detail(page):进入查看商品详情页。
  • see_user_info(page,username):进入查看用户信息。
  • exit(page):退出登录。
  • enter_chart(page):进入购物车页面。
  • view_all_orders(page):查看所有订单。
  • judge_enter_goods_list_page(page,username):验证是否进入商品列表页面。
  • judge_serch_good_success(page):验证查询商品成功。

•class goods_detail_page:商品详情页类。

  • judge_enter_goods_detail_success(page):查看进入商品详情页成功。

•class chart_page:购物车页类。

  • change_goods_number(page,number):在购物车中更改商品数量。
  • select_address(page):进入选择收货地址页,准备下单。
  • judge_enter_chart_page(page):验证是否进入购物车页面。
  • judge_number_in_chart(page,number):验证修改后的购物车某个商品数量。

•class order_page:订单页类。

  • select_address(page,address,phone):选择收货地址。
  • judge_in_order(page):验证这条订单是否生成。
  • judge_enter_select_address_page(page):验证是否进入选择收货地址页。
  • judge_enter_all_orders_page(page):验证是否进入所有订单页。

•class user_info_page:用户信息页类。

  • enter_add_adress(page):从用户信息页面进入添加用户地址页面。
  • reset_password(page):从用户信息页面进入修改密码。
  • judge_enter_user_info_page_success(page):查看进入用户信息页成功。
  • judge_having_address(page,sign):判断判断是否生成收货地址。

•class add_address_page:添加收货地址页类。

  • enter_address_info(page,address,phone):输入用户地址信息。
  • judge_enter_add_address(page):判断有无进入添加收货地址页。

•class reset_password_page:重置密码页类。

  • reset_password(page,password,repassword):重置密码。
  • reset_password_success(page):重置密码成功。
  • judge_enter_reset_password_page(page):判断是否进入重置密码页面。

每个类包括元素定位,元素操作,动态等待和断言四类方法。由于某个操作后的定位往往在另外一个页类中,动态等待和断言往往结合成一个方法中,先动态等待,等到后再断言,这个方法定义在另一类中,在本类中调用。比如注册成功后需要在登录界面中断言(注册成功页面跳转到登录页面),在登录页面定义断言方法。

测试代码

pageobject.py

代码语言:txt
复制
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: #商品详情类
  @staticmethod
  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)

2)flowobject.py

flowobject.py封装业务流操作,在test/test.py中可以采用XXXFlow.XXXBusiness()的操作形式。在这里定义了如下几个类。

类及函数说明

•userFlow:用户流。

  • Register_and_Login(self):注册然后登录。
  • reset_password(self):重置密码。

•goodsFlow:商品流。

  • search_goods(self,goods):查询商品。
  • put_goods_into_chart(self):放入购物车。
  • see_goods_detail(self):查看商品详情。

•addressFlow:收货地址流。

  • add_address(self):添加收货地址。

•orderFlow:订单流。

  • pay_order(self):下订单。
测试代码

flowobject.py

代码语言:txt
复制
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")

5 测试程序

1)test.py

类与函数说明

•class Test_Ebusiness:

  • setup_and_teardown(self):setup和teardown函数。
  • test_Register_Login(self):测试注册和登录。
  • test_search(self):测试查询商品。
  • test_put_into_chart(self):测试放入购物车。
  • test_see_goods_detail(self):测试查看商品详情。
  • test_reset_password(self):测试修改密码。
  • test_add_address(self):测试新加地址。
  • test_pay_order(self):测试下单。
  • teardown_class(self):teardown_class函数。
测试代码

test.py

代码语言:txt
复制
import sys
sys.path.append("../data")
sys.path.append("../basepage")
sys.path.append("../pageobject")
import pytest
from page import mypages
from base import base
from db import ClassDB
from data import Config
from flowobject import *
class Test_Ebusiness:
 @pytest.fixture(autouse=True)
 def setup_and_teardown(self):
 self.config=Config('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)
 yield
 self.browser.close()
 self.playwright.stop()
 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_class(self):
 try:
 db=ClassDB() 
 db.finsh_test()
 except:
 pass
if __name__=='__main__':
  pytest.main(["-sv","test.py"])

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Playwright与Selenium都是基于Web GUI自动化测试的框架,这里来介绍基于Playwright的封装的架构设计。
  • 1 目录结构
  • 2 基础操作(basepage)
    • 1)base.py
      • (1)base类
      • (2)judge类
      • (3)WaitUtils类
      • (4)异常类
    • 2)db.py
      • (1)db.py
    • 3)page.py
      • (1)page.py
  • 3 数据操作操作(data)
    • 1)data.yaml
      • (1)data.yaml
      • (2)data.py
  • 4 页面和业务操作(pageobject)
    • 1)pageobject.py
    • 2)flowobject.py
  • 5 测试程序
    • 1)test.py
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档