练手项目
1.项目计划/需求分析
- 制定测试计划,全盘考虑所有可能出现的活动以及风险
- 明确测试范围,在哪些模块进行
- 项目设定目标
- 规划活动,使用因果图/正交法/边界值等来设计测试用例
2.书写测试用例
3.代码编写
在以往的代码编写中,测试层、处理层以及基础层混在一起,降级了代码的内聚,不便于之后的修改。
我们将前置处理工作抽离到基础层。
from datetime import date, timedelta
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
import xlrd
#创建驱动控件
driver = webdriver.Chrome("./chromedriver.exe")
#获取driver
def get_driver():
return driver
# 生成时间
def date_n(n):
return str(date.today()+timedelta(days=int(n)))
# 简化driver寻找代码
def findname(element):
return driver.find_element(By.NAME,element)
#打开driver
def open(url):
# 打开网页
driver.get(url)
time.sleep(1)
# 全屏
driver.maximize_window()
#关闭driver
def close():
driver.close()
#读取信息 isHeader判读是否有标题
def readExcel(filename,index,isHeader=False):
#打开文件
xlx = xlrd.open_workbook(filename)
#定位到具体哪一张表
sheet=xlx.sheet_by_index(index)
#存储数据
data=[]
for i in range(sheet.nrows):
#如果第一行(即标题元素)存在,跳过不保存
if(i==0 & isHeader):
continue
#保存每行元素
data.append(sheet.row_values(i))
return data
在处理层进行对页面元素的定位,数据输入。
from selenium.webdriver import Keys
from quner.baseFunction import *
import time
def book_ticket(start,end,n,name,phone):
driver=get_driver()
# 目标网页地址
url="https://www.qunar.com/"
time.sleep(2)
open(url)
time.sleep(2)
driver.find_element(By.LINK_TEXT,"火车票").click()
time.sleep(1)
# 输入出发地
findname("fromStation").send_keys(Keys.BACK_SPACE)
findname("fromStation").send_keys(Keys.BACK_SPACE)
findname("fromStation").send_keys(start)
time.sleep(1)
# 输入到达地
findname("toStation").send_keys(Keys.BACK_SPACE)
findname("toStation").send_keys(Keys.BACK_SPACE)
findname("toStation").send_keys(end)
time.sleep(1)
# 输入出发日期
date_1=date_n(n)
for i in "2022-04-28":
findname("date").send_keys(Keys.BACK_SPACE)
findname("date").send_keys(date_1)
time.sleep(1)
# 点击提交按钮
driver.find_element(By.CLASS_NAME,"button-search").click()
time.sleep(3)
# 转入下一个页面
driver.find_element(By.XPATH,"//*[@id='list_listInfo']/ul[2]/li[1]/div/div[7]/a[1]/span").click()
time.sleep(2)
# 转入下一个页面
findname("contact_name").send_keys(name)
time.sleep(2)
findname("contact_phone").send_keys(phone)
time.sleep(2)
在测试层启用pytest,导入数据表内信息
import pytest
from quner.business import *
data=readExcel("data.xlsx",0,True)
#参数化
@pytest.mark.parametrize(["start","end","n","name","phone"],data)
def test_book_ticket(start,end,n,name,phone):
book_ticket(start,end,n,name,phone)
if __name__ == '__main__':
pytest.main("[-s]","testFunction.py")
data.xlsx如下,数据需要正常编写(图内是错误的)
?4测试结果
?
5.改造为po模式
po即page object,页面对象模型。就是把测试页面和测试脚本进行分离,即把页面封装成类,供测试脚本进行调用。 优点 1.页面分层页面元素和业务的逻辑进行区分 2.方便复用对象 3.每个页面都是一个独立的测试用例 4.自动化变的更容易
核心思想是通过对界面元素的封装减少冗余代码,同时在后期维护中,若元素定位发生变化, 只需要调整页面元素封装的代码,提高测试用例的可维护性、可读性。
PO模式下的分层关系为
- base层:放基础的内容,如find_element(By.NAME,"xx")缩写方法、初始化窗口等driver对页面的一系列操作
- common层:读取文件,日期处理等独立功能。属于公共层,在哪里都可以使用。
- data层:存放数据文件,如xlxs,txt等文件
- logs层:存放日志文件
- po层:页面的业务处理代码,在这里,每一个页面都要被创建为一个单独的对象。
- testcase层:存放测试代码
- reports层:存放测试报告
- config层:存放xml,yaml,properties文件等
按照规则对源代码进行整理
base层:
from selenium.webdriver.common.by import By
import time
class Base():
# 初始化
def __init__(self, driver):
self.driver = driver #重写init方法,传入driver参数
# 简化driver寻找代码
def findname(self, element):
return self.driver.find_element(By.NAME, element)
def findClassName(self, element):
return self.driver.find_element(By.CLASS_NAME, element)
def findLinkText(self, element):
return self.driver.find_element(By.LINK_TEXT, element)
def findXpath(self, element):
return self.driver.find_element(By.XPATH, element)
# 打开driver
def open(self, url):
# 打开网页
self.driver.get(url)
time.sleep(1)
# 全屏
self.driver.maximize_window()
# 关闭driver
def close(self):
self.driver.close()
common层:
from datetime import date, timedelta
import xlrd
#读取信息 isHeader判读是否有标题
def readExcel(filename,index,isHeader=False):
xlx = xlrd.open_workbook(filename)
sheet=xlx.sheet_by_index(index)
data=[]
for i in range(sheet.nrows):
if(i==0 & isHeader):
continue
data.append(sheet.row_values(i))
return data
# 生成时间
def date_n(n):
return str(date.today()+timedelta(days=int(n)))
po层:在测试过程中一共遇到了三个页面,每个页面都要视为一个单独的对象。
book_ticket_page.py
from selenium.webdriver import Keys
from quner_po.base.base import Base
import time
class bookTicketPage(Base):
#将所有有关base层的方法调用提取出来,重新定义方法进行包装传参。这样会使主体方法更加清晰,修改参
#数也更方便找到
def book_start(self):
return self.findname("fromStation")
def book_end(self):
return self.findname("toStation")
def book_date(self, date):
for i in "2022-04-28":
self.findname("date").send_keys(Keys.BACK_SPACE)
self.findname("date").send_keys(date)
def book_train(self):
return self.findLinkText("火车票")
def book_button(self):
return self.findClassName("button-search")
def book_ticket(self, start, end, date):
time.sleep(2)
self.book_train().click()
time.sleep(1)
# 输入出发地
self.book_start().clear()
self.book_start().send_keys(start)
time.sleep(1)
# 输入到达地
self.book_end().clear()
self.book_end().send_keys(end)
time.sleep(1)
# 输入出发日期
self.book_date(date)
time.sleep(1)
# 点击提交按钮
self.book_button().click()
time.sleep(3)
book_list_page.py
from quner_po.base.base import Base
import time
class bookList(Base):
def book_buy(self):
return self.findXpath("//*[@id='list_listInfo']/ul[2]/li[1]/div/div[7]/a[1]/span")
def book_list(self):
time.sleep(1)
self.book_buy().click()
time.sleep(2)
book_order_page.py
from quner_po.base.base import Base
import time
class bookOrder(Base):
def book_name(self):
return self.findname("contact_name")
def book_phone(self):
return self.findname("contact_phone")
def book_order(self,name,phone):
time.sleep(1)
self.book_name().send_keys(name)
time.sleep(1)
self.book_phone().send_keys(phone)
time.sleep(2)
testcase层:导入数据,指定测试对象
import pytest
from selenium import webdriver
import time
from quner_po.po.book_ticket_page import bookTicketPage
from quner_po.po.book_list_page import bookList
from quner_po.po.book_order_page import bookOrder
from quner_po.common.function import readExcel,date_n
#引包的格式是 from xxx.xxx.类名 import 类名/方法名
data = readExcel("../data/data.xlsx", 0, True)
class Test_Book():
def setup(self):
self.driver = webdriver.Chrome("../chromedriver.exe")
url = "https://www.qunar.com/"
# 打开网页
self.driver.get(url)
time.sleep(1)
# 全屏
self.driver.maximize_window()
@pytest.mark.parametrize(["start", "end", "n", "name", "phone"], data)
def test_book(self,start,end,n,name,phone):
#bookTicketPage继承了base类,它本身并没有要传入参数的函数,但可以传入self.driver
#是因为父类base的init方法中初始化了self.driver=driver
ticket = bookTicketPage(self.driver)
ticket.book_ticket(start,end,date_n(n))
list_b = bookList(self.driver)
list_b.book_list()
bookorder = bookOrder(self.driver)
bookorder.book_order(name,phone)
def teardown(self):
self.driver.quit()
if __name__ == '__main__':
pytest.main("[-s]","test_book.py")
|