1 目录结构
|————————————————————————
|——basepage 封装最基本的方法
|——base.py 基本操作方法
|——db.py 数据库操作方法
|——driver.py 封装驱动
|——data 测试数据及封装获取测试数据方法
|——data.py 封装获取测试数据方法
|——data.yaml 测试数据
|——pageobject 封装页面和业务流方法
|——pageobject.py 封装页面方法
|——flowobject.py 封装业务流方法
|——test 测试程序
|——test.py 测试方法
2.封装最基本的方法(basepage)
2.1 base.py
2.1.1 class base
封装最基本的方法
find_element_way(driver,by,by_str):封装通过By定位一个元素
find_elements_way(driver,by,by_str):封装通过By定位一组元素
send_keys(elnments,str):封装向文本框输入字符串,输入前先清空
save_cookies(driver):封装存储cookies
load_cookies(driver,url):封装获取cookies
excute_js_script(driver, script) :封装执行JavaScript
2.1.2 class WaitUtils
封装等待方法
wait_for_title(driver, expected_title, timeout=10):等待标题出现
wait_for_element_visible(driver, locator, timeout=10):等待元素可见
wait_for_element_clickable(driver, locator, timeout=10): 等待元素可点击
2.1.3代码源码
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
import pickle
class base:
#查找元素
def find_element_way(driver,by,by_str):
return driver.find_element(by,by_str)
#查找一组元素
def find_elements_way(driver,by,by_str):
return driver.find_elements(by,by_str)
@staticmethod
#输入,每次输入都需要清除元素
def send_keys(elnments,str):
elnments.clear()
elnments.send_keys(str)
# 保存cookies和local storage - 使用上下文管理器处理文件
@staticmethod
def save_cookies(driver):
# cookies.pkl存储Cookies信息
cookies = driver.get_cookies()
with open("cookies.pkl", "wb") as f:
pickle.dump(cookies, f)
script = "return JSON.stringify(window.localStorage);"
# localstorage.pkl存储本地存储库信息
localStorage = base.excute_js_script(driver,script)
with open("localstorage.pkl", "wb") as f:
pickle.dump(localStorage, f)
# 恢复Cookies和Local Storage
@staticmethod
def load_cookies(driver,url):
driver.get(url)
try:
with open("cookies.pkl", "rb") as f:
cookies = pickle.load(f)
for cookie in cookies:
driver.add_cookie(cookie)
with open("localstorage.pkl", "rb") as f:
localstorage_str = 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);
}}
}})({
repr(localstorage_str)});
"""
base.excute_js_script(driver,script)
# 刷新页面使状态生效
driver.refresh()
driver.get("http://127.0.0.1:8000/goods_view/")
except Exception as e:
print(f"状态恢复失败: {str(e)}")
#获取失败,获得截屏页面
@staticmethod
def excute_js_script(driver, script):
return driver.execute_script(script)
def wait_element(driver,by,string):
location=(by,string)
element = WaitUtils.wait_for_element_visible(driver,location)
assert element is not None
class WaitUtils:
@staticmethod
def wait_for_title(driver, expected_title, timeout=10):
"""
静态方法:等待页面标题变为指定值
"""
try:
WebDriverWait(driver, timeout).until(
EC.title_is(expected_title)
)
return True
except TimeoutException:
print(f"超时:页面标题不是'{expected_title}',当前标题: {driver.title}")
return False
@staticmethod
def wait_for_element_visible(driver, locator, timeout=10):
"""
等待元素可见
"""
try:
element = WebDriverWait(driver, timeout).until(
EC.visibility_of_element_located(locator)
)
return element
except TimeoutException:
print(f"超时:元素 {locator} 不可见")
return None
@staticmethod
def wait_for_element_clickable(driver, locator, timeout=10):
"""
等待元素可点击
"""
try:
element = WebDriverWait(driver, timeout).until(
EC.element_to_be_clickable(locator)
)
return element
except TimeoutException:
print(f"超时:元素 {locator} 不可点击")
return None
2.2 db.py
封装数据库操作,用于tearDown的时候清除测试数据
2.2.1 class ClassDB
connect_db(self):建立数据库连接
init_db(self,conn) :初始化数据库
close_db(self,conn) :关闭数据库
execute_query(self, query,conn,params=None) :执行SQL语句
finsh_test(self) :结束测试
2.2.2代码源码
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 db.py
2.3.1 class mydrivers
init(self,config):构造函数
config用于获取获取测试数据data.yaml
3.2.2 代码源码
#!/usr/bin/env python
#coding:utf-8
import sys
sys.path.append("../data")
from selenium import webdriver
from selenium.webdriver.edge.service import Service
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.firefox.service import Service
class mydrivers:
def __init__(self,config):
driverPach = "C:\\Lib\\"
self.config = config
brower = self.config.browser
if brower.lower() == "firefox":
service = Service(executable_path=driverPach+"geckodriver.exe")
options = webdriver.FirefoxOptions()
elif brower.lower() == "chrome":
service = Service(executable_path=driverPach+"chromedriver.exe")
options = webdriver.ChromeOptions()
elif brower.lower() == "edge":
service = Service(executable_path=driverPach+"msedgedriver.exe")
options = webdriver.EdgeOptions()
else:
print("../data/data.yaml中的信息有误")
options.add_argument('--start-maximized')
options.service = service
if brower.lower() == "firefox":
self.driver = webdriver.Firefox(options=options)
elif brower.lower() == "chrome":
self.driver = webdriver.Chrome(options=options)
elif brower.lower() == "edge":
self.driver = webdriver.Edge(options=options)
else:
print("../data/data.yaml中的信息有误")
3.测试数据及封装获取测试数据方法(data)
3.1 data.yaml
environments:
default:
browser: "chrome"
url: "http://127.0.0.1:8000"
username: "xixi"
password: "654321"
repassword: "123456"
email: "a@b.com"
address: "首体南路1号"
phone: "15434564455"
number: "3"
3.2 data.py
获取data.yaml中的数据
3.2.1代码源码
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 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封装页面和业务流方法(pageobject)
4.1 pageobject.py
封装页面
xxxpage.xxxaction()
4.2 代码源码
#!/usr/bin/env python
#coding:utf-8
import sys
sys.path.append("../basepage")
from base import base
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from base import WaitUtils
class login_page:
def login(driver,username,password):
username_field=base.find_element_way(driver,By.NAME,"username")
password_field=base.find_element_way(driver,By.NAME,"password")
submit_field=base.find_element_way(driver,By.CLASS_NAME,"form-signin")
base.send_keys(username_field,username)
base.send_keys(password_field,password)
submit_field.submit()
WaitUtils.wait_for_title(driver, "电子商务系统")
assert driver.title == "电子商务系统"
def enter_register_page(driver):
register_field=base.find_element_way(driver,By.LINK_TEXT,"注册")
register_field.click()
WaitUtils.wait_for_title(driver, "电子商务系统-注册")
assert driver.title == "电子商务系统-注册"
class register_page:
def register(driver,username,password,email):
username_field=base.find_element_way(driver,By.NAME,"username")
password_field=base.find_element_way(driver,By.NAME,"password")
email_field=base.find_element_way(driver,By.NAME,"email")
submit_field=base.find_element_way(driver,By.XPATH,"/html/body/div/form/input[2]")
base.send_keys(username_field,username)
base.send_keys(password_field,password)
base.send_keys(email_field,email)
submit_field.submit()
WaitUtils.wait_for_title(driver, "电子商务系统-登录")
assert driver.title, "电子商务系统-登录"
class goods_list_page:
#把商品放入购物车
def put_into_chart(driver):
input_link = base.find_element_way(driver,By.LINK_TEXT,"放入")
input_link.click()
chart_sing_location = (By.XPATH,"//font[@color='#FF0000' and text()='1']")
chart_sing_element = WaitUtils.wait_for_element_visible(driver,chart_sing_location)
assert chart_sing_element is not None
#查询商品
def serch_good(driver,goods):
search_input = base.find_element_way(driver,By.NAME,"good")
search_button = base.find_element_way(driver,By.XPATH,"//*[@id='navbar']/form/button")
search_input.send_keys(goods)
search_button.click()
put_link_location = (By.LINK_TEXT, "放入")
put_link_element = WaitUtils.wait_for_element_visible(driver,put_link_location)
assert put_link_element is not None
#进入查看商品详情页
def see_goods_detail(driver):
goods_detail_link = base.find_element_way(driver,By.LINK_TEXT,"查看")
goods_detail_link.click()
#验证是否进入商品详情页
goods_detail_page.judge_enter(driver)
#进入查看用户信息
def see_user_info(driver,username):
user_link = base.find_element_way(driver,By.LINK_TEXT,username)
user_link.click()
#判断进入用户信息页面
user_info_page.judge_enter(driver)
#退出
def exit(driver):
exit_link = base.find_element_way(driver,By.LINK_TEXT,"退出")
exit_link.click()
WaitUtils.wait_for_title(driver, "电子商务系统-登录")
assert driver.title, "电子商务系统-登录"
#进入购物车
def enter_chart(driver):
enter_chart_link = base.find_element_way(driver,By.PARTIAL_LINK_TEXT,"查看购物车")
enter_chart_link.click()
base.wait_element(driver,By.CLASS_NAME,"vIntegerField")
#查看所有订单
def view_all_orders(driver):
view_all_orders_link = base.find_element_way(driver,By.LINK_TEXT, "查看所有订单")
view_all_orders_link.click()
base.wait_element(driver,By.XPATH,"/html/body/div/div[2]/div/input")
class chart_page:
#在购物车中更改商品数量
def change_goods_number(driver,number):
number_field = base.find_element_way(driver,By.NAME,"count1")
change_button=base.find_element_way(driver,By.XPATH,"/html/body/div[2]/div[1]/div/table/tbody/tr/td[4]/form/input[3]")
base.send_keys(number_field,number)
change_button.click()
wait = WebDriverWait(driver, 10)
wait.until(
EC.text_to_be_present_in_element_value((By.NAME, "count1"), number)
)
#准备下单
def prapare_pay_order(driver):
pay_button = base.find_element_way(driver,By.XPATH,"/html/body/div[2]/div[1]/div/form[2]/input[2]")
pay_button.click()
base.wait_element(driver,By.XPATH,"/html/body/div[2]/div[1]/div/form[1]/input[2]")
class order_page:
#选择收货地址
def select_address(driver,address,phone):
delete_address_link = base.find_elements_way(driver,By.LINK_TEXT,"删除")
if len(delete_address_link)==0:
print("111")
#生成订单
add_address_button=base.find_element_way(driver,By.XPATH,"/html/body/div[2]/div[1]/div/form[2]/input[2]")
add_address_button.click()
add_address_page.judge_enter(driver)
add_address_page.enter_address_info(driver,address,phone)
user_info_page.judge_having_address(driver)
#选择订单
address_field = base.find_element_way(driver,By.NAME,"address")
next_button=base.find_element_way(driver,By.XPATH,"/html/body/div[2]/div[1]/div/form[1]/input[2]")
address_field.click()
next_button.click()
order_page.judge_in_order(driver)
#验证这条订单是否生成
def judge_in_order(driver):
pay_location = (By.XPATH,"/html/body/div/div[2]/div/input")
pay_element = WaitUtils.wait_for_element_visible(driver,pay_location)
assert pay_element is not None
#验证查看所有订单是否有这条订单
goods_list_page.view_all_orders(driver)
class user_info_page:
#判断进入用户信息页面
def judge_enter(driver):
base.wait_element(driver,By.ID,"add_address")
#从用户信息页面进入添加用户地址页面
def enter_add_adress(driver):
add_address_button=base.find_element_way(driver,By.ID,"add_address")
add_address_button.click()
#判断是否进入输入添加用户地址页面
add_address_page.judge_enter(driver)
#判断有无用户地址信息
def judge_having_address(driver):
base.wait_element(driver,By.LINK_TEXT,"删除")
#从用户信息页面进入修改密码
def reset_password(driver):
enter_reset_password_button = base.find_element_way(driver,By.XPATH,"/html/body/div/div[2]/div/form[1]/input[2]")
enter_reset_password_button.click()
#判断是否进入重置密码页面
reset_password_page.judge_enter(driver)
class add_address_page:
#判断是否进入输入添加用户地址页面
def judge_enter(driver):
base.wait_element(driver,By.NAME,"address")
#输入用户地址信息
def enter_address_info(driver,address,phone):
address_field=base.find_element_way(driver,By.NAME,"address")
phone_field=base.find_element_way(driver,By.NAME,"phone")
submit_field=base.find_element_way(driver,By.XPATH,"/html/body/div/form/button")
base.send_keys(address_field,address)
base.send_keys(phone_field,phone)
submit_field.submit()
#判断有无用户地址信息
user_info_page.judge_having_address(driver)
class goods_detail_page:
#判断是否进入商品详情页面
def judge_enter(driver):
base.wait_element(driver,By.XPATH,"/html/body/div[1]/div/div/div/img")
class reset_password_page:
#判断是否进入重置密码页面
def judge_enter(driver):
base.wait_element(driver,By.NAME,"oldpassword")
#重置密码
def reset_password(driver,password,repassword):
old_password_field=base.find_element_way(driver,By.NAME,"oldpassword")
new_password_field=base.find_element_way(driver,By.NAME,"newpassword")
renew_password_field=base.find_element_way(driver,By.NAME,"checkpassword")
submit_button=base.find_element_way(driver,By.XPATH,"/html/body/div/div[2]/div/form/input[5]")
base.send_keys(old_password_field,password)
base.send_keys(new_password_field,repassword)
base.send_keys(renew_password_field,repassword)
submit_button.submit()
#验证重置密码成功
base.wait_element(driver,By.XPATH,"/html/body/div/div[2]/div/form/p")
4.2 flowobject.py
封装业务流
4.2.1代码源码
#!/usr/bin/env python
#coding:utf-8
from pageobject import *
class ebusinessFlow:
def __init__(self,driver,config):
self.driver = driver
self.config = config
#自定义异常
def my_exception(self,info,error_pic):
print(info)
self.driver.save_screenshot(error_pic)
raise
#注册然后登录
def Register_and_Login(self):
try:
self.driver.get(self.config.url)
#进入注册页
login_page.enter_register_page(self.driver)
except Exception as e:
self.my_exception(f"进入注册页失败: {str(e)}","enter_register_failed.png")
try:
#注册用户
register_page.register(self.driver, self.config.username, self.config.password, self.config.email)
except Exception as e:
self.my_exception(f"注册失败: {str(e)}","register_failed.png")
try:
#用注册用户登录
login_page.login(self.driver, self.config.username, self.config.password)
except Exception as e:
self.my_exception(f"登录失败: {str(e)}","login_failed.png")
#查询商品
def search_goods(self,goods):
try:
#查询商品
goods_list_page.serch_good(self.driver, goods)
except Exception as e:
self.my_exception(f"搜索失败: {str(e)}","search_failed.png")
#放入购物车
def put_goods_into_chart(self):
try:
#把商品放入购物车
goods_list_page.put_into_chart(self.driver)
except Exception as e:
self.my_exception(f"放入购物车失败: {str(e)}","put_into_char_failed.png")
#查看商品详情
def see_goods_detail(self):
try:
#进入查看商品详情
goods_list_page.see_goods_detail(self.driver)
except Exception as e:
self.my_exception(f"查看商品详情失败: {str(e)}","see_goods_detail_failed.png")
#添加收货地址
def add_address(self):
try:
#进入查看用户信息
goods_list_page.see_user_info(self.driver,self.config.username)
except Exception as e:
self.my_exception(f"进入用户详情页失败: {str(e)}","see_user_info_fail.png")
try:
#从用户信息页面进入添加用户地址页面
user_info_page.enter_add_adress(self.driver)
except Exception as e:
self.my_exception(f"进入添加地址页失败: {str(e)}","enter_add_address_fail.png")
try:
#输入用户地址信息
add_address_page.enter_address_info(self.driver,self.config.address,self.config.phone)
except Exception as e:
self.my_exception(f"进入添加地址页失败: {str(e)}","enter_add_address_fail.png")
#重置密码
def reset_password(self):
try:
#进入查看用户信息
goods_list_page.see_user_info(self.driver,self.config.username)
except Exception as e:
self.my_exception(f"进入用户详情页失败: {str(e)}","enter_user_info_page_fail.png")
try:
#从用户信息页面进入修改密码
user_info_page.reset_password(self.driver)
except Exception as e:
self.my_exception(f"进入修改页密码失败: {str(e)}","enter_reset_password_page_fail.png")
#判断是否进入重置密码页面
try:
#重置密码
reset_password_page.reset_password(self.driver,self.config.password,self.config.repassword)
except Exception as e:
self.my_exception(f"重置密码失败: {str(e)}","reset_password_fail.png")
try:
#退出系统
goods_list_page.exit(self.driver)
except Exception as e:
self.my_exception(f"退出系统失败: {str(e)}","exit_fail.png")
try:
#用重置密码登录
login_page.login(self.driver,self.config.username,self.config.repassword)
except Exception as e:
self.my_exception(f"用重置密码登录失败: {str(e)}","login_using_new_password_fail.png")
#下单
def pay_order(self):
try:
#把商品放入购物车
goods_list_page.put_into_chart(self.driver)
except Exception as e:
self.my_exception(f"放入购物车失败: {str(e)}","put_into_char_failed.png")
try:
#进入购物车
goods_list_page.enter_chart(self.driver)
except Exception as e:
self.my_exception(f"进入购物车失败: {str(e)}","enter_chart_fail.png")
try:
#在购物车总更改商品数量
chart_page.change_goods_number(self.driver,self.config.number)
except Exception as e:
self.my_exception(f"修改商品数量失败: {str(e)}","change_number_fail.png")
try:
#准备下单
chart_page.prapare_pay_order(self.driver)
except Exception as e:
self.my_exception(f"准备下单失败: {str(e)}","prepare_pay_order_fail.png")
try:
#选择收货地址
order_page.select_address(self.driver,self.config.address,self.config.phone)
except Exception as e:
self.my_exception(f"选择收货地址失败: {str(e)}","select_address_fail.png")
5.测试程序(test)
5.1 test.py
代码源码
#!/usr/bin/env python
#coding:utf-8
import sys
sys.path.append("../data")
sys.path.append("../basepage")
sys.path.append("../pageobject")
import unittest
from driver import mydrivers
from base import base
from db import ClassDB
from data import TestConfig
from flowobject import ebusinessFlow
class CheckEbusiness(unittest.TestCase):
def setUp(self):
self.config = TestConfig('default')
d = mydrivers(self.config)
self.driver = d.driver
self.driver.implicitly_wait(5)
self.ebusiness = ebusinessFlow(self.driver,self.config)
# 测试注册和登录
def test_Register_Login(self):
self.ebusiness.Register_and_Login()
base.save_cookies(self.driver)
#测试查询商品
def test_search(self):
base.load_cookies(self.driver,self.config.url)
self.ebusiness.search_goods("茶")
#测试放入购物车
def test_put_into_chart(self):
base.load_cookies(self.driver,self.config.url)
self.ebusiness.put_goods_into_chart()
#测试查看商品详情
def test_see_goods_detail(self):
base.load_cookies(self.driver,self.config.url)
self.ebusiness.see_goods_detail()
#测试新加地址
def test_add_address(self):
base.load_cookies(self.driver,self.config.url)
self.ebusiness.add_address()
#测试修改密码
def test_reset_password(self):
base.load_cookies(self.driver,self.config.url)
self.ebusiness.reset_password()
#测试下单
def test_pay_order(self):
base.load_cookies(self.driver,self.config.url)
self.ebusiness.pay_order()
def tearDown(self):
self.driver.quit()
@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)
使用uite.addTest(classname(test_way))是为了第一个先运行"test_Register_Login"
顾翔凡言:人工智能未来的发展瓶颈在于对知识的更新。唯一不变的是变化,知识发生了变化,人工智能软件能否及时跟进变化,可能阻碍人工智能的使用。