你一定想不到,實(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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容