一步一步搭建數據驅動測試框架的過程和總結
跟吳老學了搭建自動化數據驅動的框架后,我在自己練習的時候,嘗試從簡單的程序進行一點一點的擴展和優化,到實現這個數據驅動的框架。
先說一下搭建自動化測試框架的目的:
一個是實現一個功能的自動化運行,不用每次手動的去執行一些重復性的工作,用自動化程序來代替人工,提高效率,例如回歸測試的反復執行。
二是通過把數據和對數據的操作進行封裝,減少重復代碼的書寫,以及測試數據和程序的分離,使自動化測試人員不用過多關注代碼,
維護好數據就可以進行有效的自動化測試執行,可復用性好,等等很多的好處。。。
再說一下我從無到有搭建完這個框架后的過程總結:
先去把要實現的功能在一個文件里實現,然后把某一個零散功能進行封裝,在主程序中調用封裝好的方法,把整個過程分成多個步驟,每一個步驟只實現一個封裝或優化,
就像擺積木一樣,完成一個地方之后,站在這個節點上去思考下一步我可以封裝什么,優化什么,然后向前走一步,然后在此基礎上再考慮可以優化什么,
直到搭建好這個測試框架,這個過程首先是脫離框架結構的,不去想這個框架要搭成什么樣,就想着現有的這個程序可以做哪些封裝和優化,怎么改可以讓人用起來更方便,
看上去更有條理,然后在想到可以把什么地方抽離出來做單獨的封裝時去對照一些框架結構,這個類型的封裝可以放到什么樣的包下面,一邊封裝優化,一邊進行分類,
當我們把程序該封裝的封裝,該放到配置文件中的就放到配置文件中,最后你就會發現,這個過程下來得到的就是一個測試框架。
這個過程下來之后,再從測試框架的整體架構去理解每一個模塊的功能就容易多了,因為你從無到有的去優化、封裝的時候最后得到的就是這些模塊,
然后去學不同驅動類型的測試框架時候,原理其實基本是一樣的。
下面就列一下我搭建這個框架的整體過程:
首先明確我要實現的是登錄126郵箱,並添加聯系人的功能。
步驟1--如果我不用框架的方式,直接羅列代碼的話,怎么實現呢,先來試着完成這個,
pycharm里新建一個工程-dataDrivenTestPractice1
在工程下新建一個TestScript的包
在TestScript包下新建一個TestScript的python文件
代碼:
#encoding=utf-8
#author-夏曉旭
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import traceback
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://mail.126.com')
try:
wait=WebDriverWait(driver,10,0.2)#顯示等待
driver.switch_to.frame(driver.find_element_by_xpath("//iframe[@id='x-URS-iframe']"))#切換到用戶名和密碼輸入框所在的frame元素
name=wait.until(lambda x:x.find_element_by_xpath("//input[@placeholder='郵箱帳號或手機號' and @name='email']"))
name.send_keys('xiaxiaoxu1987')
password=wait.until(lambda x:x.find_element_by_xpath("//input[@placeholder='密碼']"))
password.send_keys('gloryroad')
submit=wait.until(lambda x:x.find_element_by_xpath("//a[@id='dologin']"))
submit.click()
driver.switch_to.default_content()#在pycharm里用switch_to_default_content()會被加刪除線,out了
time.sleep(5)
assert u"退出" in driver.page_source,"no exist in page_source"
address_book_link=wait.until(lambda x:x.find_element_by_xpath("//div[text()='通訊錄']"))
address_book_link.click()
#assert u"新建聯系人" in driver.page_source
add_contact_button=wait.until(lambda x:x.find_element_by_xpath("//span[text()='新建聯系人']"))
add_contact_button.click()
contact_name=wait.until(lambda x:x.find_element_by_xpath("//a[@title='編輯詳細姓名']/preceding-sibling::div/input"))
contact_name.send_keys(u"徐鳳釵")
contact_email=wait.until(lambda x:x.find_element_by_xpath("//*[@id='iaddress_MAIL_wrap']//input"))
contact_email.send_keys("593152023@qq.com")
contact_is_star=wait.until(lambda x:x.find_element_by_xpath("//span[text()='設為星標聯系人']/preceding-sibling::span/b"))
contact_is_star.click()
contact_mobile=wait.until(lambda x:x.find_element_by_xpath("//*[@id='iaddress_TEL_wrap']//dd//input"))
contact_mobile.send_keys('18141134488')
contact_other_info=wait.until(lambda x:x.find_element_by_xpath("//textarea"))
contact_other_info.send_keys('my wife')
contact_save_button=wait.until(lambda x:x.find_element_by_xpath("//span[.='確 定']"))
contact_save_button.click()
except TimeoutException, e:
# 捕獲TimeoutException異常
print traceback.print_exc()
except NoSuchElementException, e:
# 捕獲NoSuchElementException異常
print traceback.print_exc()
except Exception, e:
# 捕獲其他異常
print traceback.print_exc()
結果:登陸、添加聯系人都ok
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/TestScript.py
Process finished with exit code 0
至此,第一步現在已經實現了,接下來看一下如何把這個程序進行程序和數據的分離呢?
先看一下程序的主要功能:
登錄郵箱-->打開聯系人頁面-->點擊添加聯系人按鈕-->在彈窗中輸入聯系人的信息-->點擊保存按鈕。
還有數據驅動的核心-->數據和程序的分離
首先,登錄郵箱的步驟可以抽離出來,進行獨立的封裝,暫定login模塊
接下來就對login的功能做一個封裝,然后在出程序里進行調用。
步驟2—把登錄的功能抽離出來,進行封裝,在主程序中調用
在工程下新建一個PageObject的包
在PageObject包下新建一個LoginPage的python文件,來封裝login的操作
代碼:
#encoding=utf-8
#author-夏曉旭
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import traceback
class LoginPage(object):
def __init__(self,driver):
self.driver=driver
def login(self):
try:
wait = WebDriverWait(driver, 10, 0.2) # 顯示等待
self.driver.switch_to.frame(self.driver.find_element_by_xpath("//iframe[@id='x-URS-iframe']")) # 切換到用戶名和密碼輸入框所在的frame元素
name = wait.until(lambda x: x.find_element_by_xpath("//input[@placeholder='郵箱帳號或手機號' and @name='email']"))
name.send_keys('xiaxiaoxu1987')
password = wait.until(lambda x: x.find_element_by_xpath("//input[@placeholder='密碼']"))
password.send_keys('gloryroad')
submit = wait.until(lambda x: x.find_element_by_xpath("//a[@id='dologin']"))
submit.click()
self.driver.switch_to.default_content() # 在pycharm里用switch_to_default_content()會被加刪除線,out了
time.sleep(5)
assert u"退出" in self.driver.page_source, "no exist in page_source"
except TimeoutException, e:
# 捕獲TimeoutException異常
print traceback.print_exc()
except NoSuchElementException, e:
# 捕獲NoSuchElementException異常
print traceback.print_exc()
except Exception, e:
# 捕獲其他異常
print traceback.print_exc()
if __name__=="__main__":
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get("http:\\mail.126.com")
login=LoginPage(driver)
login.login()
結果:登錄成功
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/PageObject/Login_page.py
Process finished with exit code 0
至此,login功能封裝好了,下面在修改主程序,調用LoginPage
TestScript.py:
#encoding=utf-8
#author-夏曉旭
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import traceback
from PageObject.Login_Page import *
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://mail.126.com')
lp=LoginPage(driver)
wait = WebDriverWait(driver, 10, 0.2) # 顯示等待
try:
lp.login()
address_book_link=wait.until(lambda x:x.find_element_by_xpath("//div[text()='通訊錄']"))
address_book_link.click()
#assert u"新建聯系人" in driver.page_source
add_contact_button=wait.until(lambda x:x.find_element_by_xpath("//span[text()='新建聯系人']"))
add_contact_button.click()
contact_name=wait.until(lambda x:x.find_element_by_xpath("//a[@title='編輯詳細姓名']/preceding-sibling::div/input"))
contact_name.send_keys(u"徐鳳釵")
contact_email=wait.until(lambda x:x.find_element_by_xpath("//*[@id='iaddress_MAIL_wrap']//input"))
contact_email.send_keys("593152023@qq.com")
contact_is_star=wait.until(lambda x:x.find_element_by_xpath("//span[text()='設為星標聯系人']/preceding-sibling::span/b"))
contact_is_star.click()
contact_mobile=wait.until(lambda x:x.find_element_by_xpath("//*[@id='iaddress_TEL_wrap']//dd//input"))
contact_mobile.send_keys('18141134488')
contact_other_info=wait.until(lambda x:x.find_element_by_xpath("//textarea"))
contact_other_info.send_keys('my wife')
contact_save_button=wait.until(lambda x:x.find_element_by_xpath("//span[.='確 定']"))
contact_save_button.click()
except TimeoutException, e:
# 捕獲TimeoutException異常
print traceback.print_exc()
except NoSuchElementException, e:
# 捕獲NoSuchElementException異常
print traceback.print_exc()
except Exception, e:
# 捕獲其他異常
print traceback.print_exc()
結果:成功
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/TestScript/TestScript.py
Process finished with exit code 0
從主程序來看,添加聯系人的動作也是可以進行封裝的 ,先來進行這部分的封裝,后續有問題再往回推導,先按照這個思路做一遍,然后再做一遍
步驟3—封裝添加聯系人的功能
在PageObject包下新建AddressBook的python文件
代碼AddressBook.py:
#encoding=utf-8
#author-夏曉旭
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import traceback
from PageObject.Login_Page import *
class AddressBook(object):
def __init__(self,driver):
self.driver=driver
def add_contact(self):
try:
wait = WebDriverWait(self.driver, 10, 0.2) # 顯示等待
address_book_link = wait.until(lambda x: x.find_element_by_xpath("//div[text()='通訊錄']"))
address_book_link.click()
# assert u"新建聯系人" in driver.page_source
add_contact_button = wait.until(lambda x: x.find_element_by_xpath("//span[text()='新建聯系人']"))
add_contact_button.click()
contact_name = wait.until(
lambda x: x.find_element_by_xpath("//a[@title='編輯詳細姓名']/preceding-sibling::div/input"))
contact_name.send_keys(u"徐鳳釵")
contact_email = wait.until(lambda x: x.find_element_by_xpath("//*[@id='iaddress_MAIL_wrap']//input"))
contact_email.send_keys("593152023@qq.com")
contact_is_star = wait.until(
lambda x: x.find_element_by_xpath("//span[text()='設為星標聯系人']/preceding-sibling::span/b"))
contact_is_star.click()
contact_mobile = wait.until(lambda x: x.find_element_by_xpath("//*[@id='iaddress_TEL_wrap']//dd//input"))
contact_mobile.send_keys('18141134488')
contact_other_info = wait.until(lambda x: x.find_element_by_xpath("//textarea"))
contact_other_info.send_keys('my wife')
contact_save_button = wait.until(lambda x: x.find_element_by_xpath("//span[.='確 定']"))
contact_save_button.click()
except TimeoutException, e:
# 捕獲TimeoutException異常
print traceback.print_exc()
except NoSuchElementException, e:
# 捕獲NoSuchElementException異常
print traceback.print_exc()
except Exception, e:
# 捕獲其他異常
print traceback.print_exc()
if __name__=="__main__":
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://mail.126.com')
lp=LoginPage(driver)
lp.login()
ab=AddressBook(driver)
ab.add_contact()
結果:成功
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/PageObject/AddressBook.py
Process finished with exit code 0
至此,添加聯系人功能粗略的封裝完了,下面在主程序中調用
TestScript.py:
#encoding=utf-8
#author-夏曉旭
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import traceback
from PageObject.Login_Page import *
from PageObject.AddressBook import *
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://mail.126.com')
loginPage=LoginPage(driver)
addressBook=AddressBook(driver)
loginPage.login()
addressBook.add_contact()
結果:成功
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/TestScript/TestScript.py
Process finished with exit code 0
至此,程序的兩個功能-登錄和添加聯系人已經粗略的封裝起來了,在主程序中可以直接調用函數就可以了,下面再回顧一下程序的主要功能:
登錄郵箱-->打開聯系人頁面-->點擊添加聯系人按鈕-->在彈窗中輸入聯系人的信息-->點擊保存按鈕。還有數據驅動的核心-->數據和程序的分離
接下來,我想嘗試把數據的部分抽離出來,下面來看下這個數據怎么分離呢?
從程序來看,調用數據的部分是在剛才封裝的兩個模塊里,Login_Page和AddressBook,看下程序是咋用數據的
Login_page:
AddressBook:
在封裝這兩個函數時,沒有留出參數,直接在函數里寫死了,這顯然是比較low的,那怎么弄呢?下面嘗試把函數中需要調用的數據用參數代替,然后在調用的時候傳參數進去。
先來修改login函數,看看怎么改成用參數傳,這時候本人突然懵逼了,這么多個不一樣的數據,沒辦法用參數啊。。。
如果要用參數傳需要把login函數進行拆分,可以看到login函數中有幾個部分是可以進行封裝起來的,比如找frame元素的功能,找到用戶名輸入框元素的功能,然后在找單個元素的函數中就可以傳遞數據給參數進行查找了
步驟4—封裝查找元素的功能
修改LoginPage.py:
#encoding=utf-8
#author-夏曉旭
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import traceback
class LoginPage(object):
def __init__(self,driver):
self.driver=driver
self.wait = WebDriverWait(self.driver, 10, 0.2) # 顯示等待
def getFrame(self,locateType,locateExpression):
frame=self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression))#"//iframe[@id='x-URS-iframe']"
return frame
def getUserName(self,locateType,locateExpression):
userName=self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression))#"//input[@placeholder='郵箱帳號或手機號' and @name='email']"
return userName
def getPassword(self,locateType,locateExpression):
password=self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression))#"//input[@placeholder='密碼']"
return password
def getLoginButton(self,locateType,locateExpression):
loginButton=self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression))#"//a[@id='dologin']"
return loginButton
if __name__=="__main__":
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get("http:\\mail.126.com")
lp=LoginPage(driver)
driver.switch_to.frame(lp.getFrame("xpath","//iframe[@id='x-URS-iframe']"))
time.sleep(2)
lp.getUserName("xpath","//input[@placeholder='郵箱帳號或手機號' and @name='email']").clear()
lp.getUserName("xpath","//input[@placeholder='郵箱帳號或手機號' and @name='email']").send_keys("xiaxiaoxu1987")
lp.getPassword("xpath","//input[@placeholder='密碼']").send_keys("gloryroad")
lp.getLoginButton("xpath","//a[@id='dologin']").click()
driver.switch_to.default_content()
time.sleep(5)
assert u"退出" in driver.page_source, "no exist in page_source"
結果:登錄成功
至此,雖然把數據作為參數傳給各個找元素的函數了,但是有一個問題。
調用的時候需要手動的去輸入查找元素需要的數據,這樣就比較麻煩,一個字母輸錯了都會找不到元素,怎么弄呢?
需要再封裝,把數據放在文件里,然后再封裝方法從文件里讀數據,這樣就需要建立一個配置文件來存數據,然后新建一個python文件來封裝讀取配置文件的方法
步驟5—把數據放到配置文件里,然后封裝方法從文件里讀數據
在工程下新建一個叫Conf的包(用來放配置相關的文件):
在Conf包下新建文件:PageObjectRepository.ini
PageObjectRepository.ini:
[126mail_login]
login_page.frame=id>x-URS-iframe
login_page.username=xpath>//input[@name='email']
login_page.password=xpath>//input[@name='password']
login_page.loginbutton=id>dologin
[126mail_homepage]
home_page.addressbook=xpath>//div[text()='通訊錄']
[126mail_addcontactspage]
addcontacts_page.createcontactsbtn=xpath>//span[text()='新建聯系人']
addcontacts_page.contactpersonname=xpath>//a[@title='編輯詳細姓名']/preceding-sibling::div/input
addcontacts_page.contactpersonemail=xpath>//*[@id='iaddress_MAIL_wrap']//input
addcontacts_page.starcontacts=xpath>//span[text()='設為星標聯系人']/preceding-sibling::span/b
addcontacts_page.contactpersonmobile=xpath>//*[@id='iaddress_TEL_wrap']//dd//input
addcontacts_page.contactpersoncomment=xpath>//textarea
addcontacts_page.savecontaceperson=xpath>//span[.='確 定']
在工程下新建一個Util的包,這個包一般用來存放工具類,如讀配置文件,查找元素方法,excel操作類,時間類,日志方法和操作,截圖,報告模板之類的。
在Util包下新建一個python文件:ParsePageObjectRepository.py 用來封裝讀取配置文件的類
#encoding=utf-8
#author-夏曉旭
from ConfigParser import ConfigParser
class ParsePageObjectRepositoryConfig(object):
def __init__(self,config_path):
self.cf=ConfigParser()#生成解析器
self.cf.read(config_path)
def getItemSection(self,sectionName):
print self.cf.items(sectionName)
return dict(self.cf.items(sectionName))
def getOptionValue(self,sectionName,optionName):#返回一個字典
print self.cf.get(sectionName,optionName)
return self.cf.get(sectionName,optionName)
if __name__=='__main__':
pp=ParsePageObjectRepositoryConfig("D:\\test\\dataDrivenTestPractice1\\Conf\\PageObjectRepository.ini")
print pp.getItemSection("126mail_login")
print pp.getOptionValue("126mail_login","login_page.username")
結果:ok
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Util/ParsePageObjectRepository.py
[('login_page.frame', 'id>x-URS-iframe'), ('login_page.username', "xpath>//input[@name='email']"), ('login_page.password', "xpath>//input[@name='password']"), ('login_page.loginbutton', 'id>dologin')]
{'login_page.loginbutton': 'id>dologin', 'login_page.username': "xpath>//input[@name='email']", 'login_page.frame': 'id>x-URS-iframe', 'login_page.password': "xpath>//input[@name='password']"}
xpath>//input[@name='email']
xpath>//input[@name='email']
Process finished with exit code 0
可以看到測試代碼中調用讀取函數的時候,參數中要手動輸入配置文件的路徑,好長的字符,如果這個路徑修改了的話,還要到這里修改,既然都封裝到這里了,索性再勤快點把路徑也配置在一個變量里算了
一般存文件路徑的變量要放在ProjectVar包下的var.py文件里,之后所有的配置文件的路徑都以變量的形式維護在這個文件中,路徑的獲取用相對路徑的方式,穩妥一些
步驟6—用變量來存配置文件的路徑
在工程下新建一個ProjectVar的包
在ProjectVar包下新建一個var.py的python文件
var.py:
#encoding=utf-8
#author-夏曉旭
import os
#獲取工程所在目錄的絕對路徑
project_path=os.path.dirname(os.path.dirname(__file__))
#獲取頁面對象庫文件的絕對路徑
page_object_repository_path=project_path.decode("utf-8")+u"/conf/PageObjectRepository.ini"
if __name__=='__main__':
#測試代碼
print "project_path:", project_path
print "page_object_repository_path:",page_object_repository_path
print os.path.exists(project_path)
print os.path.exists(page_object_repository_path)
結果:
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/ProjectVar/var.py
project_path: D:/test/dataDrivenTestPractice1
page_object_repository_path: D:/test/dataDrivenTestPractice1/conf/PageObjectRepository.ini
True
True
Process finished with exit code 0
現在再測試一下ParsePageObjectRepository.py中讀配置文件的執行
ParsePageObjectRepository.py:
#encoding=utf-8
#author-夏曉旭
from ConfigParser import ConfigParser
from ProjectVar.var import page_object_repository_path#新加的
class ParsePageObjectRepositoryConfig(object):
def __init__(self):#去掉了config_path參數
self.cf=ConfigParser()#生成解析器
self.cf.read(page_object_repository_path)#直接用變量代替
def getItemSection(self,sectionName):
print self.cf.items(sectionName)
return dict(self.cf.items(sectionName))
def getOptionValue(self,sectionName,optionName):#返回一個字典
print self.cf.get(sectionName,optionName)
return self.cf.get(sectionName,optionName)
if __name__=='__main__':
pp=ParsePageObjectRepositoryConfig()#在構造函數中已經把配置文件的地址變量初始化了
print pp.getItemSection("126mail_login")
print pp.getOptionValue("126mail_login","login_page.username")
結果:ok
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Util/ParsePageObjectRepository.py
[('login_page.frame', 'id>x-URS-iframe'), ('login_page.username', "xpath>//input[@name='email']"), ('login_page.password', "xpath>//input[@name='password']"), ('login_page.loginbutton', 'id>dologin')]
{'login_page.loginbutton': 'id>dologin', 'login_page.username': "xpath>//input[@name='email']", 'login_page.frame': 'id>x-URS-iframe', 'login_page.password': "xpath>//input[@name='password']"}
xpath>//input[@name='email']
xpath>//input[@name='email']
接下來修來login.py文件中的調用,把需要手動輸入的參數都用讀配文件代替
修改login.py:
#encoding=utf-8
#author-夏曉旭
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import traceback
from Util.ParsePageObjectRepository import *#新加
from ProjectVar.var import *#新加
class LoginPage(object):
def __init__(self,driver):
self.driver=driver
self.parse_config_file=ParsePageObjectRepositoryConfig()#新加,獲取配置文件信息
self.login_page_items=self.parse_config_file.getItemSection("126mail_login")#新加
print "self.login_page_items:",self.login_page_items
self.wait = WebDriverWait(self.driver, 10, 0.2) # 顯示等待
def getFrame(self):#參數去掉,在里面處理
locateType,locateExpression=self.login_page_items['login_page.frame'].split('>')#id>x-URS-iframe
frame=self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression))#"//iframe[@id='x-URS-iframe']"
return frame
def getUserName(self): #參數去掉,在里面處理
locateType, locateExpression = self.login_page_items['login_page.username'].split('>')#xpath>//input[@name='email']
userName=self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression))#"//input[@placeholder='郵箱帳號或手機號' and @name='email']"
return userName
def getPassword(self): #參數去掉,在里面處理
locateType, locateExpression = self.login_page_items['login_page.password'].split('>')#xpath>//input[@name='password']
password=self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression))#"//input[@placeholder='密碼']"
return password
def getLoginButton(self): #參數去掉,在里面處理
locateType, locateExpression = self.login_page_items['login_page.loginbutton'].split('>') #id>dologin
loginButton=self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression))#"//a[@id='dologin']"
return loginButton
if __name__=="__main__":
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get("http:\\mail.126.com")
lp=LoginPage(driver)
driver.switch_to.frame(lp.getFrame())
time.sleep(2)
lp.getUserName().clear()
lp.getUserName().send_keys("xiaxiaoxu1987")
lp.getPassword().send_keys("gloryroad")
lp.getLoginButton().click()
driver.switch_to.default_content()
time.sleep(5)
assert u"退出" in driver.page_source, "no exist in page_source"
至此,我們已經封裝了很多東西,也把登錄的數據放在配置文件里,實現讀取,但是距離完美還有很大的距離,但是沒有關系,只要我們清楚思路,完美只是時間問題,現在來看下這個框架還有什么問題需要優化
可以看到以下兩點可以優化:
1-在login_page.py文件中的獲取登錄頁面元素的方法中,下面這個找元素的步驟是可以封裝起來的,
self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression)),就不用在每個找元素的方法中寫這個了,而且這個找元素的步驟在給賬戶添加聯系人的功能中也會用到,把找元素的方法封裝起來就方便多了。
2-其次是在執行登錄的操作中,用戶名和密碼信息是我們手動輸入的,這個也是可以封裝起來的,如何封裝呢,起始login.py這個文件中的每個方法得到的都是登錄時所需要的元素,在進行登錄操作的時候我們手動的調用這幾個方法,獲取元素后,進行輸入字符或者點擊的動作來完成登錄操作的,那這幾個步驟就可以在另外一個文件中進行封裝,說白了就是把login_page中的獲取各個元素的方法進行一個封裝來實現登錄的功能,不用每次自己來組織零散的方法了,把他放到一個盒子里,盒子的名字叫login,每次執行這個盒子就行了,不用管里面的細節,所有的封裝都是這個道理。
步驟7—封裝查找元素的功能和login功能的進一步封裝
在開始的框架結構中可以看到,查找元素的方法可以放到Util包中
在Util包中新建ObjectMap.py文件
ObjectMap.py:
#encoding=utf-8
#author-夏曉旭
from selenium.webdriver.support.ui import WebDriverWait
#獲取單個元素對象
def getElement(driver,locateType,locateExpression):
try:
element=WebDriverWait(driver,10).until(lambda x:x.find_element(by=locateType,value=locateExpression))
return element
except Exception,e:
raise e
#獲取多個相同頁面元素對象,以list返回
def getElements(driver,locateType,locatorExpression):
try:
elements=WebDriverWait(driver,5).until(lambda x:x.find_elements(by=locateType,value=locateExpression))
return elements
except Exception,e:
raise e
if __name__=="__main__":
#測試代碼
from selenium import webdriver
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://www.baidu.com')
searchBox=getElement(driver,"xpath","//input[@id='kw']")
driver.quit()
結果:ok
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Util/ObjectMap.py
Process finished with exit code 0
至此查找元素的方法封裝起來了,下面修改Login_Page.py來調用ObjectMap的方法實現各個查找元素的方法,並且對登錄動作做個封裝。
Login_page.py:
#encoding=utf-8
#author-夏曉旭
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import traceback
from Util.ParsePageObjectRepository import *
from ProjectVar.var import *
from Util.ObjectMap import *
class LoginPage(object):
def __init__(self,driver):
self.driver=driver
self.parse_config_file=ParsePageObjectRepositoryConfig()
self.login_page_items=self.parse_config_file.getItemSection("126mail_login")
print "self.login_page_items:",self.login_page_items
self.wait = WebDriverWait(self.driver, 10, 0.2) # 顯示等待
def getFrame(self):
locateType,locateExpression=self.login_page_items['login_page.frame'].split('>')#id>x-URS-iframe
frame=getElement(self.driver,locateType,locateExpression)#"//iframe[@id='x-URS-iframe']"
return frame
def getUserName(self):
locateType, locateExpression = self.login_page_items['login_page.username'].split('>')#xpath>//input[@name='email']
userName=getElement(self.driver,locateType,locateExpression)#"//input[@placeholder='郵箱帳號或手機號' and @name='email']"
return userName
def getPassword(self):
locateType, locateExpression = self.login_page_items['login_page.password'].split('>')#xpath>//input[@name='password']
password=getElement(self.driver,locateType,locateExpression)#"//input[@placeholder='密碼']"
return password
def getLoginButton(self):
locateType, locateExpression = self.login_page_items['login_page.loginbutton'].split('>') #id>dologin
loginButton=getElement(self.driver,locateType,locateExpression)#"//a[@id='dologin']"
return loginButton
def login(self):
self.driver.switch_to.frame(self.getFrame())
self.getUserName().clear()
self.getUserName().send_keys("xiaxiaoxu1987")
self.getPassword().send_keys("gloryroad")
self.getLoginButton().click()
if __name__=="__main__":
#測試代碼
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get("http:\\mail.126.com")
lp=LoginPage(driver)
lp.login()
結果:可以登錄
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/PageObject/Login_Page.py
self.login_page_items: {'login_page.loginbutton': 'id>dologin', 'login_page.username': "xpath>//input[@name='email']", 'login_page.frame': 'id>x-URS-iframe', 'login_page.password': "xpath>//input[@name='password']"}
Process finished with exit code 0
下面我們把login函數的封裝從Login_page.py中挪出去,作為單獨的一個文件存在,把方法和調用分隔開,以后如果有變動,修改login_page.py就可以了。
步驟8—單獨封裝login方法
在工程下新建一個Action的包
在Action包下新建login.py
Login.py:
#encoding=utf-8
#author-夏曉旭
from PageObject.Login_Page import *
from selenium import webdriver
def login(driver,username,password):
lp=LoginPage(driver)
driver.switch_to.frame(lp.getFrame())
lp.getUserName().clear()
lp.getUserName().send_keys(username)
lp.getPassword().send_keys(password)
lp.getLoginButton().click()
if __name__=='__main__':
#測試代碼
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get("http://mail.126.com")
login(driver,"xiaxiaoxu1987","gloryroad")
結果:登錄成功
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Action/login.py
self.login_page_items: {'login_page.loginbutton': 'id>dologin', 'login_page.username': "xpath>//input[@name='email']", 'login_page.frame': 'id>x-URS-iframe', 'login_page.password': "xpath>//input[@name='password']"}
Process finished with exit code 0
至此,登錄功能基本封裝好了,數據和程序分離了,下面來看下添加聯系人的封裝,一步一步的實現數據和程序的分離,之前已經把添加聯系人的操作都放到AddressBook.py里面了,但是跟一開始的login_page.py情況一樣,查找元素操作、讀取配置文件數據還沒有做,下面開始做這個
步驟9—封裝添加聯系人操作
思路:
在AddressBook.py里把添加聯系人頁面需要的各個元素封裝成方法,其中找各個元素需要的xpath數據放在配置文件中,然后用一個函數來調用這些元素的方法,實現輸入字符或者點擊操作來實現添加聯系人功能
AddressBook.py:
#encoding=utf-8
#author-夏曉旭
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import traceback
from PageObject.Login_Page import *
from Action.login import *
class AddressBook(object):
def __init__(self,driver):
self.driver=driver
self.parse_config_file=ParsePageObjectRepositoryConfig()
self.address_book_page=self.parse_config_file.getItemsFromSection("126mail_homepage")
print "self.address_book_page:",self.address_book_page
self.address_book_page_itmes=self.parse_config_file.getItemsFromSection("126mail_addcontactspage")
print "self.address_book_page_itmes:", self.address_book_page_itmes
def address_book_link(self):
locateType,locateExpression = self.address_book_page['home_page.addressbook'].split(">")
print locateType,locateExpression
return getElement(self.driver,"xpath","//div[text()='通訊錄']")
def add_contact_button(self):
locateType,locateExpression=self.address_book_page_itmes['addcontacts_page.createcontactsbtn'].split(">")
print locateType,locateExpression
return getElement(self.driver,locateType,locateExpression)
def contact_name(self):
locateType,locateExpression=self.address_book_page_itmes['addcontacts_page.contactpersonname'].split(">")
print locateType, locateExpression
return getElement(self.driver, locateType, locateExpression)
def contact_email(self):
locateType, locateExpression = self.address_book_page_itmes['addcontacts_page.contactpersonemail'].split(">")
print locateType, locateExpression
return getElement(self.driver, locateType, locateExpression)
def contact_is_star(self):
locateType, locateExpression = self.address_book_page_itmes['addcontacts_page.starcontacts'].split(">")
print locateType, locateExpression
return getElement(self.driver, locateType, locateExpression)
def contact_mobile(self):
locateType, locateExpression = self.address_book_page_itmes['addcontacts_page.contactpersonmobile'].split(">")
print locateType, locateExpression
return getElement(self.driver, locateType, locateExpression)
def contact_other_info(self):
locateType, locateExpression = self.address_book_page_itmes['addcontacts_page.contactpersoncomment'].split(">")
print locateType, locateExpression
return getElement(self.driver, locateType, locateExpression)
def contact_save_button(self):
locateType, locateExpression = self.address_book_page_itmes['addcontacts_page.savecontaceperson'].split(">")
print locateType, locateExpression
return getElement(self.driver, locateType, locateExpression)
if __name__=="__main__":
driver = webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get("http://mail.126.com")
login(driver, "xiaxiaoxu1987", "gloryroad")
addressbook=AddressBook(driver)
time.sleep(5)
addressbook.address_book_link().click()
addressbook.add_contact_button().click()
addressbook.contact_name().send_keys("sam")
addressbook.contact_email().send_keys("367224698@qq.com")
addressbook.contact_is_star().click()
addressbook.contact_mobile().send_keys("18142244444")
addressbook.contact_other_info().send_keys("myself")
addressbook.contact_save_button().click()
結果:ok
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/PageObject/AddressBook.py
self.login_page_items: {'login_page.loginbutton': 'id>dologin', 'login_page.username': "xpath>//input[@name='email']", 'login_page.frame': 'id>x-URS-iframe', 'login_page.password': "xpath>//input[@name='password']"}
self.address_book_page: {'home_page.addressbook': "xpath>//div[text()='\xe9\x80\x9a\xe8\xae\xaf\xe5\xbd\x95']"}
self.address_book_page_itmes: {'addcontacts_page.createcontactsbtn': "xpath>//span[text()='\xe6\x96\xb0\xe5\xbb\xba\xe8\x81\x94\xe7\xb3\xbb\xe4\xba\xba']", 'addcontacts_page.contactpersonmobile': "xpath>//*[@id='iaddress_TEL_wrap']//dd//input", 'addcontacts_page.contactpersonemail': "xpath>//*[@id='iaddress_MAIL_wrap']//input", 'addcontacts_page.contactpersoncomment': 'xpath>//textarea', 'addcontacts_page.contactpersonname': "xpath>//a[@title='\xe7\xbc\x96\xe8\xbe\x91\xe8\xaf\xa6\xe7\xbb\x86\xe5\xa7\x93\xe5\x90\x8d']/preceding-sibling::div/input", 'addcontacts_page.savecontaceperson': "xpath>//span[.='\xe7\xa1\xae \xe5\xae\x9a']", 'addcontacts_page.starcontacts': "xpath>//span[text()='\xe8\xae\xbe\xe4\xb8\xba\xe6\x98\x9f\xe6\xa0\x87\xe8\x81\x94\xe7\xb3\xbb\xe4\xba\xba']/preceding-sibling::span/b"}
xpath //div[text()='通訊錄']
xpath //span[text()='新建聯系人']
xpath //a[@title='編輯詳細姓名']/preceding-sibling::div/input
xpath //*[@id='iaddress_MAIL_wrap']//input
xpath //span[text()='設為星標聯系人']/preceding-sibling::span/b
xpath //*[@id='iaddress_TEL_wrap']//dd//input
xpath //textarea
xpath //span[.='確 定']
現在,我們已經把添加聯系人頁面的各個元素的操作封裝起來了,在測試代碼中進行了調用,同login功能的封裝一樣,我們把對添加聯系人頁面的各個元素的操作封裝在另一個文件中,在主程序中直接調用就可以了,方便操作。
步驟10—單獨封裝addressBook的添加聯系人功能
在Action包下新建add_contact.py文件
add_contact.py:
#encoding=utf-8
#author-夏曉旭
from PageObject.AddressBook import *
from selenium import webdriver
def add_contact(driver):
driver.switch_to.default_content()
addressbook = AddressBook(driver)
addressbook.address_book_link().click()
addressbook.add_contact_button().click()
addressbook.contact_name().send_keys("sam")
addressbook.contact_email().send_keys("367224698@qq.com")
addressbook.contact_is_star().click()
addressbook.contact_mobile().send_keys("18142244444")
addressbook.contact_other_info().send_keys("myself")
addressbook.contact_save_button().click()
if __name__=='__main__':
driver=webdriver.Firefox(executable_path="c:\\geckodriver")
driver.get("http://mail.126.com")
login(driver, "xiaxiaoxu1987", "gloryroad")
add_contact(driver)
結果:
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Action/add_contact.py
self.login_page_items: {'login_page.loginbutton': 'id>dologin', 'login_page.username': "xpath>//input[@name='email']", 'login_page.frame': 'id>x-URS-iframe', 'login_page.password': "xpath>//input[@name='password']"}
Process finished with exit code 0
進一步封裝,把輸入的部分用參數代替
#encoding=utf-8
#author-夏曉旭
from PageObject.AddressBook import *
from selenium import webdriver
def add_contact(driver,name="",email="",is_star=True,mobile="",otherinfo=""):
driver.switch_to.default_content()
addressbook = AddressBook(driver)
addressbook.address_book_link().click()
addressbook.add_contact_button().click()
addressbook.contact_name().send_keys(name)
addressbook.contact_email().send_keys(email)
if is_star==True:
addressbook.contact_is_star().click()
addressbook.contact_mobile().send_keys(mobile)
addressbook.contact_other_info().send_keys(otherinfo)
addressbook.contact_save_button().click()
if __name__=='__main__':
driver=webdriver.Firefox(executable_path="c:\\geckodriver")
driver.get("http://mail.126.com")
login(driver, "xiaxiaoxu1987", "gloryroad")
add_contact(driver,"xiaxiaoxu","367224698@qq.com",True,"13333334444","gloryroad")
driver.quit()
結果:ok
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Action/add_contact.py
self.login_page_items: {'login_page.loginbutton': 'id>dologin', 'login_page.username': "xpath>//input[@name='email']", 'login_page.frame': 'id>x-URS-iframe', 'login_page.password': "xpath>//input[@name='password']"}
Process finished with exit code 0
至此,我們已經封裝了大部分功能,現在來試一下主程序中調用這幾個功能:
TestScript.py:
#encoding=utf-8
#author-夏曉旭
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import traceback
from PageObject.Login_Page import *
from PageObject.AddressBook import *
from Action.add_contact import *
from Action.login import *
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://mail.126.com')
login(driver, "xiaxiaoxu1987", "gloryroad")
add_contact(driver,"xiaxiaoxu","367224698@qq.com",True,"13333334444","gloryroad")
driver.quit()
結果:可以正常運行。
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/TestScript/TestScript.py
Process finished with exit code 0
從主程序中的調用來看,還是有一些數據是需要手動來輸入的,如用戶名、密碼、需要添加的聯系人信息,如果需要添加多個聯系人的話,還需要多次輸入,下一步就來看怎么把這部分數據和程序分離開,也是存到文件中,這次來放Excel中,然后用操作excel的方法來出取數據。
步驟11-封裝excel操作
創建一個excel文件,第一個sheet來放126賬號的信息
第二個sheet放聯系人:
在工程下新建一個TestData的包,把excel文件放到該包下
Excel.py:
#encoding=utf-8
#author-夏曉旭
# encoding=utf-8
from openpyxl import load_workbook
from openpyxl.styles import Border, Side, Font
import time
from ProjectVar.var import *
class parseExcel(object):
def __init__(self, excelPath):
self.excelPath = excelPath
self.workbook = load_workbook(excelPath) # 加載excel
self.sheet = self.workbook.active # 獲取第一個sheet
self.font = Font(color=None)
self.colorDict = {"red": 'FFFF3030', "green": 'FF008B00'}
# 設置當前要操作的sheet對象,使用index來獲取相應的sheet
def set_sheet_by_index(self, sheet_index):
sheet_name = self.workbook.get_sheet_names()[sheet_index]
self.sheet = self.workbook.get_sheet_by_name(sheet_name)
return self.sheet
# 獲取當前默認sheet的名字
def get_default_sheet(self):
return self.sheet.title
# 設置當前要操作的sheet對象,使用sheet名稱來獲取相應的sheet
def set_sheet_by_name(self, sheet_name):
sheet = self.workbook.get_sheet_by_name(sheet_name)
self.sheet = sheet
return self.sheet
# 獲取默認sheet中最大的行數
def get_max_row_no(self):
return self.sheet.max_row
# 獲取默認 sheet 的最大列數
def get_max_col_no(self):
return self.sheet.max_column
# 獲取默認sheet的最小(起始)行號
def get_min_row_no(self):
return self.sheet.min_row
# 獲取默認sheet的最小(起始)列號
def get_min_col_no(self):
return self.sheet.min_column
# 獲取默認 sheet 的所有行對象,
def get_all_rows(self):
return list(self.sheet.iter_rows())
# return list(self.rows)也可以
# 獲取默認sheet中的所有列對象
def get_all_cols(self):
return list(self.sheet.iter_cols())
# return list(self.sheet.columns)也可以
# 從默認sheet中獲取某一列,第一列從0開始
def get_single_col(self, col_no):
return self.get_all_cols()[col_no]
# 從默認sheet中獲取某一行,第一行從0開始
def get_single_row(self, row_no):
return self.get_all_rows()[row_no]
# 從默認sheet中,通過行號和列號獲取指定的單元格,注意行號和列號從1開始
def get_cell(self, row_no, col_no):
return self.sheet.cell(row=row_no, column=col_no)
# 從默認sheet中,通過行號和列號獲取指定的單元格中的內容,注意行號和列號從1開始
def get_cell_content(self, row_no, col_no):
return self.sheet.cell(row=row_no, column=col_no).value
# 從默認sheet中,通過行號和列號向指定單元格中寫入指定內容,注意行號和列號從1開始
# 調用此方法的時候,excel不要處於打開狀態
def write_cell_content(self, row_no, col_no, content, font=None):
self.sheet.cell(row=row_no, column=col_no).value = content
self.workbook.save(self.excelPath)
return self.sheet.cell(row=row_no, column=col_no).value
# 從默認sheet中,通過行號和列號向指定單元格中寫入當前日期,注意行號和列號從1開始
# 調用此方法的時候,excel不要處於打開狀態
def write_cell_current_time(self, row_no, col_no):
time1 = time.strftime("%Y-%m-%d %H:%M:%S")
self.sheet.cell(row=row_no, column=col_no).value = str(time1)
self.workbook.save(self.excelPath)
return self.sheet.cell(row=row_no, column=col_no).value
def save_excel_file(self):
self.workbook.save(self.excelPath)
if __name__ == '__main__':
#測試代碼
p = parseExcel(test_data_excel_path)
print u"獲取默認sheet:", p.get_default_sheet()
print u"設置sheet索引為1", p.set_sheet_by_index(1)
print u"獲取默認sheet:", p.get_default_sheet()
print u"設置sheet索引為0", p.set_sheet_by_index(0)
print u"獲取默認sheet:", p.get_default_sheet()
print u"最大行數:", p.get_max_row_no()
print u"最大列數:", p.get_max_col_no()
print u"最小起始行數:", p.get_min_row_no()
print u"最小起始列數:", p.get_min_col_no()
print u"所有行對象:", p.get_all_rows()
print u"所有列對象:", p.get_all_cols()
print u"獲取某一列(2):", p.get_single_col(2)
print u"獲取某一行(1):", p.get_single_row(1)
print u"取得行號和列號(2,2)單元格:", p.get_cell(2, 2)
print u"取得行號和列號單元格的內容(2,2)", p.get_cell_content(2, 2)
print u"行號和列號寫入內容(11,11):'xiaxiaoxu'", p.write_cell_content(11, 11, 'xiaxiaoxu') #
print u"行號和列號寫入當前日期(13,13):", p.write_cell_current_time(13, 13)
結果:ok
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Util/Excel.py
獲取默認sheet: 聯系人
設置sheet索引為1 <Worksheet "\u8054\u7cfb\u4eba">
獲取默認sheet: 聯系人
設置sheet索引為0 <Worksheet "126\u8d26\u53f7">
獲取默認sheet: 126賬號
最大行數: 3
最大列數: 6
最小起始行數: 1
最小起始列數: 1
所有行對象: [(<Cell u'126\u8d26\u53f7'.A1>, <Cell u'126\u8d26\u53f7'.B1>, <Cell u'126\u8d26\u53f7'.C1>, <Cell u'126\u8d26\u53f7'.D1>, <Cell u'126\u8d26\u53f7'.E1>, <Cell u'126\u8d26\u53f7'.F1>), (<Cell u'126\u8d26\u53f7'.A2>, <Cell u'126\u8d26\u53f7'.B2>, <Cell u'126\u8d26\u53f7'.C2>, <Cell u'126\u8d26\u53f7'.D2>, <Cell u'126\u8d26\u53f7'.E2>, <Cell u'126\u8d26\u53f7'.F2>), (<Cell u'126\u8d26\u53f7'.A3>, <Cell u'126\u8d26\u53f7'.B3>, <Cell u'126\u8d26\u53f7'.C3>, <Cell u'126\u8d26\u53f7'.D3>, <Cell u'126\u8d26\u53f7'.E3>, <Cell u'126\u8d26\u53f7'.F3>)]
所有列對象: [(<Cell u'126\u8d26\u53f7'.A1>, <Cell u'126\u8d26\u53f7'.A2>, <Cell u'126\u8d26\u53f7'.A3>), (<Cell u'126\u8d26\u53f7'.B1>, <Cell u'126\u8d26\u53f7'.B2>, <Cell u'126\u8d26\u53f7'.B3>), (<Cell u'126\u8d26\u53f7'.C1>, <Cell u'126\u8d26\u53f7'.C2>, <Cell u'126\u8d26\u53f7'.C3>), (<Cell u'126\u8d26\u53f7'.D1>, <Cell u'126\u8d26\u53f7'.D2>, <Cell u'126\u8d26\u53f7'.D3>), (<Cell u'126\u8d26\u53f7'.E1>, <Cell u'126\u8d26\u53f7'.E2>, <Cell u'126\u8d26\u53f7'.E3>), (<Cell u'126\u8d26\u53f7'.F1>, <Cell u'126\u8d26\u53f7'.F2>, <Cell u'126\u8d26\u53f7'.F3>)]
獲取某一列(2): (<Cell u'126\u8d26\u53f7'.C1>, <Cell u'126\u8d26\u53f7'.C2>, <Cell u'126\u8d26\u53f7'.C3>)
獲取某一行(1): (<Cell u'126\u8d26\u53f7'.A2>, <Cell u'126\u8d26\u53f7'.B2>, <Cell u'126\u8d26\u53f7'.C2>, <Cell u'126\u8d26\u53f7'.D2>, <Cell u'126\u8d26\u53f7'.E2>, <Cell u'126\u8d26\u53f7'.F2>)
取得行號和列號(2,2)單元格: <Cell u'126\u8d26\u53f7'.B2>
取得行號和列號單元格的內容(2,2) xiaxiaoxu1987
行號和列號寫入內容(11,11):'xiaxiaoxu' xiaxiaoxu
行號和列號寫入當前日期(13,13): 2018-07-10 21:28:14
Process finished with exit code 0
至此,對excel操作就封裝完了,下面在主程序中試一下對數據的讀取
TestScript.py:
#encoding=utf-8
#author-夏曉旭
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import traceback
from PageObject.Login_Page import *
from PageObject.AddressBook import *
from Action.add_contact import *
from Action.login import *
from ProjectVar.var import *
from Util.Excel import *
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://mail.126.com')
pe=parseExcel(test_data_excel_path)
pe.set_sheet_by_name(u"126賬號")
print pe.get_default_sheet()
rows=pe.get_all_rows()[1:]
for id,row in enumerate(rows):
if row[4].value =='y':
username = row[1].value
password = row[2].value
print username, password
try:
login(driver,username,password)
pe.set_sheet_by_name(u"聯系人")
print pe.get_default_sheet()
rows1=pe.get_all_rows()[1:]
print "rows1:",rows1
for id1,row in enumerate(rows1):
if row[7].value == 'y':
try:
#print row[1].value,row[2].value,row[3].value,row[4].value,row[5].value
#print "execute1"
add_contact(driver,row[1].value,row[2].value,row[3].value,row[4].value,row[5].value)
print "assert word:",row[6].value in driver.page_source
print row[6].value
pe.write_cell_content(id1+2,10,"pass")
except Exception,e:
print u"異常信息:",e.message
pe.write_cell_content(id1+2,10,"fail")
else:
pe.write_cell_content(id1+2,10,u"忽略")
continue
except Exception,e:
pe.set_sheet_by_name(u"126賬號")
print u"異常信息:",e
pe.write_cell_content(id+2,5,"fail")
else:
pe.set_sheet_by_name(u"126賬號")
pe.write_cell_content(id+2,6,u"忽略")
continue
結果:執行ok
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/TestScript/TestScript.py
126賬號
xiaxiaoxu1987 gloryroad
聯系人
rows1: [(<Cell u'\u8054\u7cfb\u4eba'.A2>, <Cell u'\u8054\u7cfb\u4eba'.B2>, <Cell u'\u8054\u7cfb\u4eba'.C2>, <Cell u'\u8054\u7cfb\u4eba'.D2>, <Cell u'\u8054\u7cfb\u4eba'.E2>, <Cell u'\u8054\u7cfb\u4eba'.F2>, <Cell u'\u8054\u7cfb\u4eba'.G2>, <Cell u'\u8054\u7cfb\u4eba'.H2>, <Cell u'\u8054\u7cfb\u4eba'.I2>, <Cell u'\u8054\u7cfb\u4eba'.J2>), (<Cell u'\u8054\u7cfb\u4eba'.A3>, <Cell u'\u8054\u7cfb\u4eba'.B3>, <Cell u'\u8054\u7cfb\u4eba'.C3>, <Cell u'\u8054\u7cfb\u4eba'.D3>, <Cell u'\u8054\u7cfb\u4eba'.E3>, <Cell u'\u8054\u7cfb\u4eba'.F3>, <Cell u'\u8054\u7cfb\u4eba'.G3>, <Cell u'\u8054\u7cfb\u4eba'.H3>, <Cell u'\u8054\u7cfb\u4eba'.I3>, <Cell u'\u8054\u7cfb\u4eba'.J3>), (<Cell u'\u8054\u7cfb\u4eba'.A4>, <Cell u'\u8054\u7cfb\u4eba'.B4>, <Cell u'\u8054\u7cfb\u4eba'.C4>, <Cell u'\u8054\u7cfb\u4eba'.D4>, <Cell u'\u8054\u7cfb\u4eba'.E4>, <Cell u'\u8054\u7cfb\u4eba'.F4>, <Cell u'\u8054\u7cfb\u4eba'.G4>, <Cell u'\u8054\u7cfb\u4eba'.H4>, <Cell u'\u8054\u7cfb\u4eba'.I4>, <Cell u'\u8054\u7cfb\u4eba'.J4>), (<Cell u'\u8054\u7cfb\u4eba'.A5>, <Cell u'\u8054\u7cfb\u4eba'.B5>, <Cell u'\u8054\u7cfb\u4eba'.C5>, <Cell u'\u8054\u7cfb\u4eba'.D5>, <Cell u'\u8054\u7cfb\u4eba'.E5>, <Cell u'\u8054\u7cfb\u4eba'.F5>, <Cell u'\u8054\u7cfb\u4eba'.G5>, <Cell u'\u8054\u7cfb\u4eba'.H5>, <Cell u'\u8054\u7cfb\u4eba'.I5>, <Cell u'\u8054\u7cfb\u4eba'.J5>)]
assert word: True
lily@qq.com
assert word: True
李四
Process finished with exit code 0
Excel結果:
至此,該框架大部分功能已經封裝好了,下面再搞一下日志模塊,使程序在執行的時候能夠打印日志
步驟12—添加日志log模塊
在Conf包下新建Logger.conf日志的配置文件,其中配置了日志器、處理器和格式器,日志這一塊具體的細節后續會專門列一個整理
#logger.conf
###############################################
[loggers]
keys=root,example01,example02
[logger_root]
level=DEBUG
handlers=hand01,hand02
[logger_example01]
handlers=hand01,hand02
qualname=example01
propagate=0
[logger_example02]
handlers=hand01,hand03
qualname=example02
propagate=0
###############################################
[handlers]
keys=hand01,hand02,hand03
[handler_hand01]
class=StreamHandler
level=INFO
formatter=form01
args=(sys.stderr,)
[handler_hand02]
class=FileHandler
level=DEBUG
formatter=form01
args=('DataDrivenFrameWork.log', 'a')
[handler_hand03]
class=handlers.RotatingFileHandler
level=INFO
formatter=form01
args=('DataDrivenFrameWork.log', 'a', 10*1024*1024, 5)
###############################################
[formatters]
keys=form01,form02
[formatter_form01]
format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
datefmt=%Y-%m-%d %H:%M:%S
[formatter_form02]
format=%(name)-12s: %(levelname)-8s %(message)s
datefmt=%Y-%m-%d %H:%M:%S
在Util包下新建log.py文件,來封裝日志的操作
Log.py:
#encoding=utf-8
#author-夏曉旭
import logging
import logging.config
from ProjectVar.var import *
#讀取日志的配置文件
logging.config.fileConfig(project_path+"\\Conf\\Logger.conf")
#選擇一個日志格式
logger=logging.getLogger("example02")
def error(message):
#打印debug級別的信息
logger.error(message)
def info(message):
#打印info級別的信息
logger.info(message)
def warning(message):
#打印warning級別的信息
logger.warning(message)
if __name__=="__main__":
#測試代碼
info("hi")
print "config file path:",project_path+"\\Conf\\Logger.conf"
error("world!")
warning("gloryroad!")
結果:ok
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Util/log.py
2018-07-11 21:32:12 log.py[line:19] INFO hi
config file path: D:\test\dataDrivenTestPractice1\Conf\Logger.conf
2018-07-11 21:32:12 log.py[line:15] ERROR world!
2018-07-11 21:32:12 log.py[line:23] WARNING gloryroad!
Process finished with exit code 0
日志的封裝已經ok了,下面修改主程序並且調用日志。
TestScript.py:
#encoding=utf-8
#author-夏曉旭
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import traceback
from PageObject.Login_Page import *
from PageObject.AddressBook import *
from Action.add_contact import *
from Action.login import *
from ProjectVar.var import *
from Util.Excel import *
from Util.log import *
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://mail.126.com')
pe=parseExcel(test_data_excel_path)
pe.set_sheet_by_name(u"126賬號")
print pe.get_default_sheet()
rows=pe.get_all_rows()[1:]
for id,row in enumerate(rows):
if row[4].value =='y':
username = row[1].value
password = row[2].value
print username, password
try:
login(driver,username,password)
pe.set_sheet_by_name(u"聯系人")
print pe.get_default_sheet()
rows1=pe.get_all_rows()[1:]
print "rows1:",rows1
test_data_pass_flag=True#結果表示,用於最后寫入excel結果
for id1,row in enumerate(rows1):
if row[7].value == 'y':
try:
#print row[1].value,row[2].value,row[3].value,row[4].value,row[5].value
print "log0711",row[1],row[1].value
print "log0711",type(row[1].value)
#進行添加聯系人的實際操作
add_contact(driver,row[1].value,row[2].value,row[3].value,row[4].value,row[5].value)
print "assert word:",row[6].value
assert row[6].value in driver.page_source
pe.write_cell_content(id1+2,10,"pass")#assert沒有報錯,說明斷言成功
except Exception,e:
#print u"異常信息01",e.message
pe.write_cell_content(id1+2,10,"fail")
test_data_pass_flag=False#代碼走到這里,說明有異常,測試失敗
info(u"異常信息01" + e.message) # 輸出日志
else:#說明標識為'n',忽略該數據
pe.write_cell_content(id1+2,10,u"忽略")
continue
if test_data_pass_flag ==True:#如果標識是True,說明結果是成功的
pe.set_sheet_by_name(u"126賬號")
pe.write_cell_content(id+2,5,"成功")
else:#說明標識是False
pe.set_sheet_by_name(u"126賬號")
pe.write_cell_content(id+2,5,"失敗")
except Exception,e:
pe.set_sheet_by_name(u"126賬號")
#print u"異常信息02:",e
pe.write_cell_content(id+2,6,"fail")
info(u"異常信息02:"+e.message)#輸出日志
time.sleep(2)
driver.quit()
else:#走這個分支,說明標識為"n"
pe.set_sheet_by_name(u"126賬號")
pe.write_cell_content(id+2,6,u"忽略")
continue
結果:運行ok
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/TestScript/TestScript.py
126賬號
xiaxiaoxu1987 gloryroad
2018-07-11 22:55:25 log.py[line:19] INFO login successfully
聯系人
rows1: [(<Cell u'\u8054\u7cfb\u4eba'.A2>, <Cell u'\u8054\u7cfb\u4eba'.B2>, <Cell u'\u8054\u7cfb\u4eba'.C2>, <Cell u'\u8054\u7cfb\u4eba'.D2>, <Cell u'\u8054\u7cfb\u4eba'.E2>, <Cell u'\u8054\u7cfb\u4eba'.F2>, <Cell u'\u8054\u7cfb\u4eba'.G2>, <Cell u'\u8054\u7cfb\u4eba'.H2>, <Cell u'\u8054\u7cfb\u4eba'.I2>, <Cell u'\u8054\u7cfb\u4eba'.J2>), (<Cell u'\u8054\u7cfb\u4eba'.A3>, <Cell u'\u8054\u7cfb\u4eba'.B3>, <Cell u'\u8054\u7cfb\u4eba'.C3>, <Cell u'\u8054\u7cfb\u4eba'.D3>, <Cell u'\u8054\u7cfb\u4eba'.E3>, <Cell u'\u8054\u7cfb\u4eba'.F3>, <Cell u'\u8054\u7cfb\u4eba'.G3>, <Cell u'\u8054\u7cfb\u4eba'.H3>, <Cell u'\u8054\u7cfb\u4eba'.I3>, <Cell u'\u8054\u7cfb\u4eba'.J3>), (<Cell u'\u8054\u7cfb\u4eba'.A4>, <Cell u'\u8054\u7cfb\u4eba'.B4>, <Cell u'\u8054\u7cfb\u4eba'.C4>, <Cell u'\u8054\u7cfb\u4eba'.D4>, <Cell u'\u8054\u7cfb\u4eba'.E4>, <Cell u'\u8054\u7cfb\u4eba'.F4>, <Cell u'\u8054\u7cfb\u4eba'.G4>, <Cell u'\u8054\u7cfb\u4eba'.H4>, <Cell u'\u8054\u7cfb\u4eba'.I4>, <Cell u'\u8054\u7cfb\u4eba'.J4>), (<Cell u'\u8054\u7cfb\u4eba'.A5>, <Cell u'\u8054\u7cfb\u4eba'.B5>, <Cell u'\u8054\u7cfb\u4eba'.C5>, <Cell u'\u8054\u7cfb\u4eba'.D5>, <Cell u'\u8054\u7cfb\u4eba'.E5>, <Cell u'\u8054\u7cfb\u4eba'.F5>, <Cell u'\u8054\u7cfb\u4eba'.G5>, <Cell u'\u8054\u7cfb\u4eba'.H5>, <Cell u'\u8054\u7cfb\u4eba'.I5>, <Cell u'\u8054\u7cfb\u4eba'.J5>)]
log0711 <Cell u'\u8054\u7cfb\u4eba'.B2> lily
log0711 <type 'unicode'>
assert word: lily@qq.com
Process finished with exit code 0
login.py文件里也可以在執行登錄動作后打個日志,提示登錄成功。
至此,主程序中實現了讀取數據、登錄郵箱、添加聯系人、往excel里寫入測試結果,基本的功能已經搞定了,下面再搞一個地方,就接近完美了,就是對時間的封裝,在程序中調用時間函數寫入指定的時間格式。
步驟13—常用時間操作的封裝
在Util包下新建FormatTime.py
FormatTime.py
#encoding=utf-8
#author-夏曉旭
#encoding=utf-8
import time
from datetime import timedelta,date
def date_time_chinese():
print u"returns the current time string,format for YYYY年mm月dd日HH時MM分SS秒"
return time.strftime("%Y年%m月%d日 %H時%M分%S秒",time.localtime())
def date_chinese():
print u"returns the current time string, format for YYYY年mm月dd日"
return time.strftime("%Y年%m月%d日",time.localtime())
def time_chinese():
print u"returns the current time string,format for HH時 MM分 SS秒"
return time.strftime("%H時%M分%S秒",time.localtime())
def date_time():
print "returns the current time string, format for YYYY-mm-dd HH:MM:SS"
return time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
def date_time_slash():
print "returns the current time string,format for YYYY/mm/dd HH:MM:SS"
return time.strftime("%Y/%m/%d %H:%M:%S",time.localtime())
def dates():
print "returns the current time string,format for YYYY-mm-dd"
return time.strftime("%Y-%m-%d",time.localtime())
def date_slash():
print "returns the current time string,format for YYYY/mm/dd"
return time.strftime("%Y/%m/%d",time.localtime())
def times():
print "returns the current time string, format for HH:MM:SS"
return time.strftime("%H:%M:%S",time.localtime())
def year():
print "returns the current time string,format for year"
return time.strftime("%Y",time.localtime())
def month():
print "returns the current time string,format for month"
return time.strftime("%m",time.localtime())
def day():
print "returns the current time string,format for day"
return time.strftime("%d",time.localtime())
def hour():
print "returns the current time string, format for Hour"
return time.strftime("%H",time.localtime())
def minute():
print "returns the current time string,format for minute"
return time.strftime("%M",time.localtime())
def seconds():
print "return the current time string,format for seconds"
return time.strftime("%S",time.localtime())
def str_to_tuple(stime):
print "returns the string variable into time tuples"
return time.strptime(stime,"%Y-%m-%d %H:%M:%S")
def add_date(day_num):
today=date.today()
print "returns the current date-%s and a time interval-%s" %(today,day_num)
times=today+timedelta(days=day_num)
return times
def sub_date(day_num):
today=date.today()
print "returns the current date-%s minus one time interval-%s" %(today,day_num)
times=today-timedelta(days=day_num)
return times
if __name__=='__main__':
#測試代碼
print date_time_chinese()
print date_chinese()
print time_chinese()
print date_time()
print date_time_slash()
print dates()
print date_slash()
print times()
print year()
print month()
print day()
print hour()
print minute()
print seconds()
time1=time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
print str_to_tuple(time1)
print add_date(2)
print sub_date(2)
結果:ok,pycharm里中文不需要轉碼,在notepad里運行需要轉碼
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Util/FormatTime.py
returns the current time string,format for YYYY年mm月dd日HH時MM分SS秒
2018年07月11日 23時01分36秒
returns the current time string, format for YYYY年mm月dd日
2018年07月11日
returns the current time string,format for HH時 MM分 SS秒
23時01分36秒
returns the current time string, format for YYYY-mm-dd HH:MM:SS
2018-07-11 23:01:36
returns the current time string,format for YYYY/mm/dd HH:MM:SS
2018/07/11 23:01:36
returns the current time string,format for YYYY-mm-dd
2018-07-11
returns the current time string,format for YYYY/mm/dd
2018/07/11
returns the current time string, format for HH:MM:SS
23:01:36
returns the current time string,format for year
2018
returns the current time string,format for month
07
returns the current time string,format for day
11
returns the current time string, format for Hour
23
returns the current time string,format for minute
01
return the current time string,format for seconds
36
returns the string variable into time tuples
time.struct_time(tm_year=2018, tm_mon=7, tm_mday=11, tm_hour=23, tm_min=1, tm_sec=36, tm_wday=2, tm_yday=192, tm_isdst=-1)
returns the current date-2018-07-11 and a time interval-2
2018-07-13
returns the current date-2018-07-11 minus one time interval-2
2018-07-09
Process finished with exit code 0
修改主程序,調用時間函數,打印時間
TestScript.py:
#encoding=utf-8
#author-夏曉旭
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import traceback
from PageObject.Login_Page import *
from PageObject.AddressBook import *
from Action.add_contact import *
from Action.login import *
from ProjectVar.var import *
from Util.Excel import *
from Util.log import *
from Util.FormatTime import *
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://mail.126.com')
pe=parseExcel(test_data_excel_path)
pe.set_sheet_by_name(u"126賬號")
print pe.get_default_sheet()
rows=pe.get_all_rows()[1:]
for id,row in enumerate(rows):
if row[4].value =='y':
username = row[1].value
password = row[2].value
print username, password
try:
login(driver,username,password)
pe.set_sheet_by_name(u"聯系人")
print pe.get_default_sheet()
rows1=pe.get_all_rows()[1:]
print "rows1:",rows1
test_data_pass_flag=True#結果表示,用於最后寫入excel結果
for id1,row in enumerate(rows1):
if row[7].value == 'y':
try:
#print row[1].value,row[2].value,row[3].value,row[4].value,row[5].value
print "log0711",row[1],row[1].value
print "log0711",type(row[1].value)
#進行添加聯系人的實際操作
add_contact(driver,row[1].value,row[2].value,row[3].value,row[4].value,row[5].value)
pe.write_cell_content(id1 + 2, 9, date_time())
print "assert word:",row[6].value
assert row[6].value in driver.page_source
pe.write_cell_content(id1+2,10,"pass")#assert沒有報錯,說明斷言成功
except Exception,e:
#print u"異常信息01",e.message
pe.write_cell_content(id1+2,10,"fail")
pe.write_cell_content(id1+2,9,date_time())
test_data_pass_flag=False#代碼走到這里,說明有異常,測試失敗
info(u"異常信息01" + e.message) # 輸出日志
else:#說明標識為'n',忽略該數據
pe.write_cell_content(id1+2,10,u"忽略")
pe.write_cell_content(id1 + 2, 9,date_time())
continue
if test_data_pass_flag ==True:#如果標識是True,說明結果是成功的
pe.set_sheet_by_name(u"126賬號")
pe.write_cell_content(id+2,6,"成功")
else:#說明標識是False
pe.set_sheet_by_name(u"126賬號")
pe.write_cell_content(id+2,6,"失敗")
except Exception,e:
pe.set_sheet_by_name(u"126賬號")
#print u"異常信息02:",e
pe.write_cell_content(id+2,6,"fail")
info(u"異常信息02:"+e.message)#輸出日志
time.sleep(2)
driver.quit()
else:#走這個分支,說明標識為"n"
pe.set_sheet_by_name(u"126賬號")
pe.write_cell_content(id+2,6,u"忽略")
continue
結果: ok
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/TestScript/TestScript.py
126賬號
xiaxiaoxu1987 gloryroad
2018-07-11 23:17:39 log.py[line:19] INFO login successfully
聯系人
rows1: [(<Cell u'\u8054\u7cfb\u4eba'.A2>, <Cell u'\u8054\u7cfb\u4eba'.B2>, <Cell u'\u8054\u7cfb\u4eba'.C2>, <Cell u'\u8054\u7cfb\u4eba'.D2>, <Cell u'\u8054\u7cfb\u4eba'.E2>, <Cell u'\u8054\u7cfb\u4eba'.F2>, <Cell u'\u8054\u7cfb\u4eba'.G2>, <Cell u'\u8054\u7cfb\u4eba'.H2>, <Cell u'\u8054\u7cfb\u4eba'.I2>, <Cell u'\u8054\u7cfb\u4eba'.J2>), (<Cell u'\u8054\u7cfb\u4eba'.A3>, <Cell u'\u8054\u7cfb\u4eba'.B3>, <Cell u'\u8054\u7cfb\u4eba'.C3>, <Cell u'\u8054\u7cfb\u4eba'.D3>, <Cell u'\u8054\u7cfb\u4eba'.E3>, <Cell u'\u8054\u7cfb\u4eba'.F3>, <Cell u'\u8054\u7cfb\u4eba'.G3>, <Cell u'\u8054\u7cfb\u4eba'.H3>, <Cell u'\u8054\u7cfb\u4eba'.I3>, <Cell u'\u8054\u7cfb\u4eba'.J3>), (<Cell u'\u8054\u7cfb\u4eba'.A4>, <Cell u'\u8054\u7cfb\u4eba'.B4>, <Cell u'\u8054\u7cfb\u4eba'.C4>, <Cell u'\u8054\u7cfb\u4eba'.D4>, <Cell u'\u8054\u7cfb\u4eba'.E4>, <Cell u'\u8054\u7cfb\u4eba'.F4>, <Cell u'\u8054\u7cfb\u4eba'.G4>, <Cell u'\u8054\u7cfb\u4eba'.H4>, <Cell u'\u8054\u7cfb\u4eba'.I4>, <Cell u'\u8054\u7cfb\u4eba'.J4>), (<Cell u'\u8054\u7cfb\u4eba'.A5>, <Cell u'\u8054\u7cfb\u4eba'.B5>, <Cell u'\u8054\u7cfb\u4eba'.C5>, <Cell u'\u8054\u7cfb\u4eba'.D5>, <Cell u'\u8054\u7cfb\u4eba'.E5>, <Cell u'\u8054\u7cfb\u4eba'.F5>, <Cell u'\u8054\u7cfb\u4eba'.G5>, <Cell u'\u8054\u7cfb\u4eba'.H5>, <Cell u'\u8054\u7cfb\u4eba'.I5>, <Cell u'\u8054\u7cfb\u4eba'.J5>)]
log0711 <Cell u'\u8054\u7cfb\u4eba'.B2> lily
log0711 <type 'unicode'>
returns the current time string, format for YYYY-mm-dd HH:MM:SS
assert word: lily@qq.com
returns the current time string, format for YYYY-mm-dd HH:MM:SS
returns the current time string, format for YYYY-mm-dd HH:MM:SS
returns the current time string, format for YYYY-mm-dd HH:MM:SS
Process finished with exit code 0
Excel寫入結果:
總結:
現在我們就是先從組裝零散的功能實現一個較大的功能,然后把較大的功能組織成一個更大的功能,到最后在主程序中我們看到的就是獨立大塊兒功能的組合,看起來很整潔,簡單,可讀性高,也方便維護。
這樣我們把整個框架從零散的羅列代碼到封裝成一塊塊的功能,把數據和程序做一個分離,把某一個獨立的功能進行封裝,整合,在這個過程中,就把搭框架的步驟熟悉了,知道了封裝成幾大塊的來龍去脈和帶來的好處,之后再搭建測試框架的時候,就直接按照這幾大塊來搭就行了,相對會比較容易接受這個思路和邏輯還有它的必要性,從根本上理解了為什么要搭建這樣的測試框架,以及這個測試框架的原理,進而會舉一反三,擴展到其他類型的測試框架當中。
多動手實踐~
下面是數據驅動框架結構:
數據驅動框架結構:
Action:
封裝的操作元素的函數,如login,添加聯系人。。。
conf:
日志配置文件
定位元素配置文件
數據庫配置文件
PageObject:
一個頁面是一個類,類的方法可以獲取頁面上的相關元素
ProjectVar:
工程路徑
工程相關的全局變量
TestData:(文件或excel)
測試用例
測試數據
TestScript:
運行測試框架的主程序:入口,主要讀取測試數據的文件
記錄測試結果。
Util-工具類
功能:
讀取配置文件
excel工具類
時間類
查找元素的方法
讀取定位元素配置文件的方法
日志方法
日志操作
截圖
報告模板
需要框架源碼的可以評論區留下郵箱~