你一定想不到虑鼎,實(shí)現(xiàn)一個(gè)Python+Selenium的自動(dòng)化測(cè)試框架就這么簡(jiǎn)單!

首先你得知道什么是Selenium键痛?

Selenium是一個(gè)基于瀏覽器的自動(dòng)化測(cè)試工具炫彩,它提供了一種跨平臺(tái)、跨瀏覽器的端到端的web自動(dòng)化解決方案絮短。Selenium主要包括三部分:Selenium IDE江兢、Selenium WebDriver 和Selenium Grid。

  • Selenium IDE:Firefox的一個(gè)擴(kuò)展丁频,它可以進(jìn)行錄制回放杉允,并把錄制的操作以多種語(yǔ)言(例如java、python等)的形式導(dǎo)出成測(cè)試用例席里。

  • Selenium WebDriver:提供Web自動(dòng)化所需的API叔磷,主要用作瀏覽器控制、頁(yè)面元素選擇和調(diào)試奖磁。不同的瀏覽器需要不同的WebDriver改基。

  • Selenium Grid:提供了在不同機(jī)器的不同瀏覽器上運(yùn)行selenium測(cè)試的能力。

下面我會(huì)使用思維導(dǎo)圖目錄結(jié)構(gòu)介紹基礎(chǔ)測(cè)試框架咖为,編寫測(cè)試用例進(jìn)行功能測(cè)試用例秕狰,希望對(duì)您的學(xué)習(xí)有所幫助嵌洼。

設(shè)計(jì)思路

框架采用python3 + selenium3 + PO + yaml + ddt + unittest等技術(shù)編寫成基礎(chǔ)測(cè)試框架,能適應(yīng)日常測(cè)試工作需要封恰。

  1. 使用Page Object模式將頁(yè)面定位和業(yè)務(wù)操作分開(kāi)麻养,分離測(cè)試對(duì)象(元素對(duì)象)和測(cè)試腳本(用例腳本),一個(gè)頁(yè)面建一個(gè)對(duì)象類诺舔,提高用例的可維護(hù)性鳖昌;

  2. 使用yaml管理頁(yè)面控件元素?cái)?shù)據(jù)和測(cè)試用例數(shù)據(jù)。例如元素ID等發(fā)生變化時(shí)低飒,不需要去修改測(cè)試代碼许昨,只需要在對(duì)應(yīng)的頁(yè)面元素yaml文件中修改即可;

  3. 分模塊管理褥赊,互不影響糕档,隨時(shí)組裝,即拿即用拌喉。

測(cè)試框架分層設(shè)計(jì)

把常見(jiàn)的操作和查找封裝成基礎(chǔ)類速那,不管是什么產(chǎn)品,可直接拿來(lái)復(fù)用

  • 業(yè)務(wù)層主要是封裝對(duì)象頁(yè)面類尿背,一個(gè)頁(yè)面建一個(gè)類端仰,業(yè)務(wù)層頁(yè)面繼承基礎(chǔ)層

  • 用例層針對(duì)產(chǎn)品頁(yè)面功能進(jìn)行構(gòu)造模擬執(zhí)行測(cè)試

  • 框架層提供基礎(chǔ)組件,支撐整個(gè)流程執(zhí)行及功能擴(kuò)展田藐,給用例層提供各頁(yè)面的元素?cái)?shù)據(jù)荔烧、用例測(cè)試數(shù)據(jù),測(cè)試報(bào)告輸出等

測(cè)試框架目錄結(jié)構(gòu)

如下思維導(dǎo)圖目錄結(jié)構(gòu)介紹:

編寫用例方法

如果對(duì)軟件測(cè)試汽久、接口測(cè)試鹤竭、自動(dòng)化測(cè)試、面試經(jīng)驗(yàn)交流景醇。感興趣可以關(guān)注我們愛(ài)碼小士臀稚,公眾號(hào)內(nèi)會(huì)有不定期的發(fā)放免費(fèi)的資料鏈接,這些資料都是從各個(gè)技術(shù)網(wǎng)站搜集啡直、整理出來(lái)的烁涌,如果你有好的學(xué)習(xí)資料可以私聊發(fā)我,我會(huì)注明出處之后分享給大家酒觅。


testinfo:
- id: test_login001
title: 登錄測(cè)試
info: 打開(kāi)抽屜首頁(yè)
testcase:
- element_info: login-link-a
find_type: ID
operate_type: click
info: 打開(kāi)登錄對(duì)話框
- element_info: mobile
find_type: ID
operate_type: send_keys
info: 輸入手機(jī)號(hào)
- element_info: mbpwd
find_type: ID
operate_type: send_keys
info: 輸入密碼
- element_info: //input[@class='keeplogin']
find_type: XPATH
operate_type: click
info: 單擊取消自動(dòng)登錄單選框
- element_info: //span[text()='登錄']
find_type: XPATH
operate_type: click
info: 單擊登錄按鈕
- element_info: userProNick
find_type: ID
operate_type: perform
info: 鼠標(biāo)懸停賬戶菜單
- element_info: //a[@class='logout']
find_type: XPATH
operate_type: click
info: 選擇退出
check:
- element_info: //div[@class='box-mobilelogin']
/div[1]/span
find_type: XPATH
info: 檢查輸入手機(jī)號(hào)或密碼撮执,登錄異常提示
- element_info: userProNick
find_type: ID
info: 成功登錄
- element_info: reg-link-a
find_type: ID
info: 檢查退出登錄是否成功
login.yaml

例如,我們要新增登錄功能測(cè)試用例:

首先舷丹,只需在testyaml目錄下新增一個(gè)頁(yè)面對(duì)象yaml文件抒钱,參考login.yaml格式編寫即可。這些文件是提供給封裝頁(yè)面對(duì)象類調(diào)用并執(zhí)行定位識(shí)別操作。


-
id: test_login001.1
detail : 手機(jī)號(hào)和密碼為空登錄
screenshot : phone_pawd_empty
data:
phone: ""
password: ""
check :
- 手機(jī)號(hào)不能為空
-
id: test_login001.2
detail : 手機(jī)號(hào)為空登錄
screenshot : phone_empty
data :
phone: ""
password : aa
check :
- 手機(jī)號(hào)不能為空
-
id: test_login001.3
detail : 密碼為空登錄
screenshot : pawd_empty
data :
phone : 13511112222
password: ""
check :
- 密碼不能為空
-
id: test_login001.4
detail : 非法手機(jī)號(hào)登錄
screenshot : phone_error
data :
phone : abc
password: aa
check :
- 手機(jī)號(hào)格式不對(duì)
-
id: test_login001.5
detail : 手機(jī)號(hào)或密碼不匹配
screenshot : pawd_error
data :
phone : 13511112222
password: aa
check :
- 賬號(hào)密碼錯(cuò)誤
-
id: test_login001.6
detail : 手機(jī)號(hào)和密碼正確
screenshot : phone_pawd_success
data :
phone : 13865439800
password: ********
check :
- yingoja
login_data.yaml

login_data.yaml

其次谋币,在testdata目錄下新增一個(gè)login_data.yaml文件提供給登錄接口傳參的測(cè)試數(shù)據(jù)仗扬,編寫格式參考login_data.yaml文件。


#!/usr/bin/env python
# _*_ coding:utf-8 _*_
__author__ = 'YinJia' 
import os,sys
sys.path.append(os.path.dirname(os.path.dirname
(os.path.dirname(__file__))))
from config import setting
from selenium.webdriver.support.select import Select
from selenium.webdriver.common.action_chains 
import ActionChains
from selenium.webdriver.common.by import By
from public.page_obj.base import Page
from time import sleep
from public.models.GetYaml import getyaml
testData = getyaml(setting.TEST_Element_YAML
+ '/' + 'login.yaml')
class login(Page):
"""
用戶登錄頁(yè)面
"""
url = '/'
dig_login_button_loc = (By.ID, testData.
get_elementinfo(0)) def dig_login(self):
"""
首頁(yè)登錄
:return:
"""
self.find_element(*self.dig_login_button_loc)
.click() sleep(1)
# 定位器蕾额,通過(guò)元素屬性定位元素對(duì)象
# 手機(jī)號(hào)輸入框
login_phone_loc = (By.ID,testData.
get_elementinfo(1)) # 密碼輸入框
login_password_loc = (By.ID,testData.
get_elementinfo(2)) # 取消自動(dòng)登錄
keeplogin_button_loc = (By.XPATH,testData.
get_elementinfo(3)) # 單擊登錄
login_user_loc = (By.XPATH,testData.
get_elementinfo(4)) # 退出登錄
login_exit_loc = (By.ID, testData.
get_elementinfo(5)) # 選擇退出
login_exit_button_loc = (By.XPATH,testData.
get_elementinfo(6))def login_phone(self,phone):
"""
登錄手機(jī)號(hào)
:param username:
:return:
"""
self.find_element(*self.login_phone_loc).
send_keys(phone)def login_password(self,password):
"""
登錄密碼
:param password:
:return:
"""
self.find_element(*self.login_password_loc).
send_keys(password) def keeplogin(self):
"""
取消單選自動(dòng)登錄
:return:
"""
self.find_element(*self.keeplogin_button_loc).
click()def login_button(self):
"""
登錄按鈕
:return:
"""
self.find_element(*self.login_user_loc).click()
def login_exit(self):
"""
退出系統(tǒng)
:return:
"""
above = self.find_element(*self.login_exit_loc)
ActionChains(self.driver).move_to_element(above).
perform() sleep(2)
self.find_element(*self.login_exit_button_loc)
.click()def user_login(self,phone,password):
"""
登錄入口
:param username: 用戶名
:param password: 密碼
:return:
"""
self.open()
self.dig_login()
self.login_phone(phone)
self.login_password(password)
sleep(1)
self.keeplogin()
sleep(1)
self.login_button()
sleep(1)
phone_pawd_error_hint_loc = (By.XPATH,testData.
get_CheckElementinfo(0))
user_login_success_loc = (By.ID,testData.
get_CheckElementinfo(1))
exit_login_success_loc = (By.ID,testData.
get_CheckElementinfo(2))
# 手機(jī)號(hào)或密碼錯(cuò)誤提示
def phone_pawd_error_hint(self):
return self.find_element(*self.phone_pawd_error_
hint_loc).text# 登錄成功用戶名
def user_login_success_hint(self):
return self.find_element(*self.user_login_
success_loc).text # 退出登錄
def exit_login_success_hint(self):
return self.find_element(*self.exit_login_
success_loc).textloginPage.py

然后早芭,在page_obj目錄下新增一個(gè)loginPage.py文件,是用來(lái)封裝登錄頁(yè)面對(duì)象類诅蝶,執(zhí)行登錄測(cè)試流程操作退个。


#!/usr/bin/env python
# _*_ coding:utf-8 _*_
__author__ = 'YinJia' 
import os,sys
sys.path.append(os.path.dirname(os.path.
dirname(__file__)))
import unittest,ddt,yaml
from config import setting
from public.models import myunit,screenshot
from public.page_obj.loginPage import login
from public.models.log import Log
try:
f =open(setting.TEST_DATA_YAML + '/' + 'login_data.yaml',encoding='utf-8')
testData = yaml.load(f)
except FileNotFoundError as file:
log = Log()
log.error("文件不存在:{0}".format(file))
@ddt.ddt
class Demo_UI(myunit.MyTest):
"""抽屜新熱榜登錄測(cè)試"""
def user_login_verify(self,phone,password):
"""
用戶登錄
:param phone: 手機(jī)號(hào)
:param password: 密碼
:return:
"""
login(self.driver).user_login(phone,password)
def exit_login_check(self):
"""
退出登錄
:return:
"""
login(self.driver).login_exit()
@ddt.data(*testData)
def test_login(self,datayaml):
"""
登錄測(cè)試
:param datayaml: 加載login_data登錄測(cè)試數(shù)據(jù)
:return:
"""
log = Log()
log.info("當(dāng)前執(zhí)行測(cè)試用例ID-> {0} ; 測(cè)試點(diǎn)-> {1}".format(datayaml['id'],datayaml['detail']))
# 調(diào)用登錄方法
self.user_login_verify(datayaml['data']['phone'],
datayaml['data']['password'])
po = login(self.driver)
if datayaml['screenshot'] == 'phone_pawd_success':
log.info("檢查點(diǎn)-> {0}".format
(po.user_login_success_hint()))
self.assertEqual(po.user_login_success_hint(), datayaml['check'][0], "成功登錄,返回實(shí)際結(jié)果是->: {0}".format(po.user_login_success_hint()))
log.info("成功登錄调炬,返回實(shí)際結(jié)果是->: {0}".format(po.user_login_success_hint()))
screenshot.insert_img(self.driver, datayaml
['screenshot'] + '.jpg')
log.info("-----> 開(kāi)始執(zhí)行退出流程操作")
self.exit_login_check()
po_exit = login(self.driver)
log.info("檢查點(diǎn)-> 找到{0}元素,表示退出成功语盈!".format(po_exit.exit_login_success_hint()))
self.assertEqual(po_exit.exit_login_success_hint(),
'注冊(cè)',"退出登錄,返回實(shí)際結(jié)果是->: {0}".format(po_exit.exit_login_success_hint()))
log.info("退出登錄缰泡,返回實(shí)際結(jié)果是->: {0}".format(po_exit.exit_login_success_hint()))
else:
log.info("檢查點(diǎn)-> {0}".format(po.phone
_pawd_error_hint()))
self.assertEqual(po.phone_pawd_error_hint(),
datayaml['check'][0] , "異常登錄刀荒,返回實(shí)際結(jié)果是->: {0}".format(po.phone_pawd_error_hint()))
log.info("異常登錄,返回實(shí)際結(jié)果是->: {0}".format(po.phone_pawd_error_hint()))
screenshot.insert_img(self.driver,datayaml
['screenshot'] + '.jpg')
if __name__=='__main__':
unittest.main()
login_sta.py

最后棘钞,在testcase目錄下創(chuàng)建測(cè)試用例文件login_sta.py缠借,采用ddt數(shù)據(jù)驅(qū)動(dòng)讀取yaml測(cè)試數(shù)據(jù)文件

綜上所述,編寫用例方法只需要按以上四個(gè)步驟創(chuàng)建->編寫即可武翎。

執(zhí)行如下主程序烈炭,可看輸出的實(shí)際結(jié)果溶锭。


#!/usr/bin/env python
# _*_ coding:utf-8 _*_
__author__ = 'YinJia' import os,sys
sys.path.append(os.path.dirname(__file__))
from config import setting
import unittest,time
from package.HTMLTestRunner import HTMLTestRunner
from public.models.newReport import new_report
from public.models.sendmail import send_mail
# 測(cè)試報(bào)告存放文件夾宝恶,如不存在,則自動(dòng)創(chuàng)建
一個(gè)report目錄 if not os.path.exists(setting.TEST_REPORT):os.makedirs
(setting.TEST_REPORT + '/' + "screenshot")
def add_case(test_path=setting.TEST_DIR):
"""加載所有的測(cè)試用例"""
discover = unittest.defaultTestLoader.discover
(test_path, pattern='*_sta.py')
return discover
def run_case(all_case,result_path=setting.TEST_REPORT):
"""執(zhí)行所有的測(cè)試用例"""
now = time.strftime("%Y-%m-%d %H_%M_%S")
filename = result_path + '/' + now + 'result.html'
fp = open(filename,'wb')
runner = HTMLTestRunner(stream=fp,title='
抽屜新熱榜UI自動(dòng)化測(cè)試報(bào)告',
description='環(huán)境:windows 7 瀏覽器:chrome',
tester='Jason')
runner.run(all_case)
fp.close()
report = new_report(setting.TEST_REPORT)
#調(diào)用模塊生成最新的報(bào)告
send_mail(report) #調(diào)用發(fā)送郵件模塊
if __name__ =="__main__":
cases = add_case()
run_case(cases)

測(cè)試結(jié)果展示

HTML報(bào)告日志

HTML報(bào)告點(diǎn)擊截圖趴捅,彈出截圖

測(cè)試報(bào)告通過(guò)的日志

自動(dòng)截圖存放指定的目錄

郵件測(cè)試報(bào)告

擴(kuò)展閱讀

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末综芥,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子猎拨,更是在濱河造成了極大的恐慌膀藐,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件红省,死亡現(xiàn)場(chǎng)離奇詭異额各,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)吧恃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門虾啦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事傲醉∮眨” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵硬毕,是天一觀的道長(zhǎng)呻引。 經(jīng)常有香客問(wèn)我,道長(zhǎng)吐咳,這世上最難降的妖魔是什么苞七? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮挪丢,結(jié)果婚禮上蹂风,老公的妹妹穿的比我還像新娘。我一直安慰自己乾蓬,他們只是感情好惠啄,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著任内,像睡著了一般撵渡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上死嗦,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天趋距,我揣著相機(jī)與錄音,去河邊找鬼越除。 笑死节腐,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的摘盆。 我是一名探鬼主播翼雀,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼孩擂!你這毒婦竟也來(lái)了狼渊?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤类垦,失蹤者是張志新(化名)和其女友劉穎狈邑,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蚤认,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡米苹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了烙懦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片驱入。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡赤炒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出亏较,到底是詐尸還是另有隱情莺褒,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布雪情,位于F島的核電站遵岩,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏巡通。R本人自食惡果不足惜尘执,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望宴凉。 院中可真熱鬧誊锭,春花似錦、人聲如沸弥锄。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)籽暇。三九已至温治,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間戒悠,已是汗流浹背熬荆。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绸狐,地道東北人卤恳。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像六孵,于是被迫代替她去往敵國(guó)和親纬黎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容