一、UI自動(dòng)化測試基礎(chǔ)知識(shí)點(diǎn)(元素定位暫不寫)
1、 技術(shù)架構(gòu):python+selenium;
2、 自動(dòng)化測試webdriver運(yùn)行原理:
自動(dòng)化測試代碼發(fā)送請求給瀏覽器的驅(qū)動(dòng),瀏覽器驅(qū)動(dòng)自動(dòng)識(shí)別代碼,解析后發(fā)送給瀏覽器,瀏覽器執(zhí)行驅(qū)動(dòng)發(fā)來的指令,完成自動(dòng)化測試的工作;
3、 webdriver長用屬性以及方法:
driver.title---查看標(biāo)題
driver.Current_url----查看地址
driver.windows_handles----查看瀏覽器句柄
4、 close()與quit()區(qū)別:
close---退出當(dāng)前頁面,quit---退出瀏覽器;
5、 webelement屬性以及方法:
屬性:
id:標(biāo)識(shí);
size:寬高;
rect:寬高和坐標(biāo);
tag_name:標(biāo)簽名稱;
text:文本內(nèi)容;
方法:
Send_size:輸入內(nèi)容
Click:點(diǎn)擊
Clear:清除
Is_selected:是否被選中;
6、 form表單操作:
流程:定位表單元素、輸出測試數(shù)據(jù)、判斷表單元素屬性、獲得表單元素屬性、提交表單進(jìn)行驗(yàn)證;
7、 下拉列表操作:
Select_by_value():根據(jù)值選擇
Select_by_index():根據(jù)索引選擇
Select_by_visible_text():根據(jù)文本選擇
彈窗處理:
1、alert:普通提示框。切換至彈窗--self.driver.swich_to.alert
2、confirm:刪除數(shù)據(jù)提示框。切換至彈窗--self.driver.swich_to.alert
3、prompt:輸入文本內(nèi)容提示框。切換至彈窗--self.driver.swich_to.alert
以上三種彈窗的方法:accept()--接受、dismiss()--取消、text()--顯示文本、send_keys()--輸入內(nèi)容;
三種等待:
1、wait:遇到環(huán)境網(wǎng)絡(luò)等不穩(wěn)定時(shí)候,如果不做處理,代碼會(huì)因?yàn)闆]有找到元素而報(bào)錯(cuò),這個(gè)時(shí)候需要使用wait等待方式;
2、time.sleep:讓當(dāng)前的線程睡眠,用于調(diào)試腳本;
3、implicitly_wait:隱式等待,最開始設(shè)置一次全程有效,按規(guī)定時(shí)間內(nèi)網(wǎng)頁加載完成,才執(zhí)行下一步,否則會(huì)拋出異常;
4、webdriverwait:顯式等待;參數(shù):driver--webdriver實(shí)例、timeout--設(shè)置超時(shí)時(shí)間、poll_frequency--調(diào)試方法中的時(shí)間,默認(rèn)0.5秒。方法:until--等待時(shí)間內(nèi),每隔一段時(shí)間傳入這個(gè)方法,查看返回結(jié)果是不是TRUE、message--如果超時(shí),就傳入message異常;
鼠標(biāo)操作:
之前定位的時(shí)候,用到了click點(diǎn)擊元素,selenium除了click模擬鼠標(biāo)單擊操作外,還提供了雙擊、右擊、懸停、拖動(dòng)等操作,使用這些要導(dǎo)入ActionChains類:
from selenium.webdriver.common.action_chains import ActionChains。
ActionChains提供的操作如下:
* perform() 執(zhí)行所有 ActionChains 中存儲(chǔ)的行為
* context_click() 右擊
* double_click() 雙擊
* drag_and_drop() 拖拽到某個(gè)元素
* move_to_element() 鼠標(biāo)懸停
* drag_and_drop_by_offset()拖拽到某個(gè)坐標(biāo)
示例:
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from time import sleep
driver=webdriver.Chrome()
driver.get("https://www.baidu.com/")
driver.maximize_window()
driver.find_element_by_css_selector("#kw").send_keys("鋤禾")
#獲取搜索框元素對象
element=driver.find_element_by_css_selector("#kw")
sleep(3)
#雙擊
ActionChains(driver).double_click(element).perform()
sleep(2)
#右擊
ActionChains(driver).context_click(element).perform()
#鼠標(biāo)懸停
#懸停在設(shè)置上
above=driver.find_element_by_css_selector(".pf")
ActionChains(driver).move_to_element(above).perform()
sleep(3)
driver.quit()
鍵盤操作:
1.模擬鍵盤的操作需要先導(dǎo)入鍵盤模塊:
from selenium.webdriver.common.keys import Keys
2.Keys()類提供了鍵盤上幾乎所有按鍵的方法。前面了解到,send_keys()方法可以用來模擬鍵盤 輸入, 除此 之外, 我們還可以用它來輸入鍵盤上的按鍵甚至是組合鍵, 如 Ctrl+A、 Ctrl+C 等。
3.常見的鍵盤操作:
send_keys(Keys.BACK_SPACE) #刪除鍵(BackSpace)
send_keys(Keys.SPACE) #空格鍵(Space)
send_keys(Keys.TAB) #制表鍵(Tab)
send_keys(Keys.ESCAPE) #回退鍵(Esc)
send_keys(Keys.ENTER) #回車鍵(Enter)
send_keys(Keys.CONTROL,‘a(chǎn)’) #全選(Ctrl+A)
send_keys(Keys.CONTROL,‘c’) #復(fù)制(Ctrl+C)
send_keys(Keys.CONTROL,‘x’) #剪切(Ctrl+X)
send_keys(Keys.CONTROL,‘v’) #粘貼(Ctrl+V)
send_keys(Keys.F1) #鍵盤 F1
send_keys(Keys.F12) #鍵盤 F12
二、自動(dòng)化項(xiàng)目實(shí)戰(zhàn)
1、需求分析與用例設(shè)計(jì):深度挖掘需求,設(shè)計(jì)測試用例
2、項(xiàng)目架構(gòu)設(shè)計(jì):合理設(shè)計(jì)目錄以及包結(jié)構(gòu):
Testcase測試用例:用來存放測試用例;
Data測試數(shù)據(jù):數(shù)據(jù)驅(qū)動(dòng)實(shí)現(xiàn)測試,用于存放數(shù)據(jù);
Logs:log日志;
Config:配置文件;
Reports:測試報(bào)告;
Screenshots:截屏;
Lib:第三方庫;
Utils:工具類;
Main.py:用于執(zhí)行測試;
3、PyAutoGUI:圖形用戶界面自動(dòng)化測試工具,通過X,Y坐標(biāo)確定目標(biāo)位置,控制鼠標(biāo)鍵盤發(fā)送虛擬點(diǎn)擊,完成按鈕以及表單等操作;
Pyautogui.position():確定鼠標(biāo)當(dāng)前位置;
Pyautogui.moveTo(x,y[,duration=t]):移動(dòng);
舉例:
from selenium import webdriver
from time import sleep
import pyautogui
'''
定位按鈕時(shí),元素定位技術(shù)無法定位時(shí),可以選擇使用pyautogui技術(shù)通過x,y坐標(biāo)進(jìn)行定位
'''
def test():
driver = webdriver.Chrome()
driver.get("http://jpress.io/user/register")
driver.maximize_window()
sleep(2)
elem = driver.find_element_by_id("agree")
rect = elem.rect #獲取坐標(biāo)
pyautogui.click(rect['x']+30,rect['y']+130)
sleep(4)
4、解決驗(yàn)證碼驗(yàn)證問題:
1、通過pytesseract某塊和PIL模塊進(jìn)行驗(yàn)證
具體步驟:1、獲取整個(gè)頁面;2、 獲得驗(yàn)證碼坐標(biāo)位置數(shù)據(jù);3、根據(jù)坐標(biāo)位置摳圖;4、使用pytesseract驗(yàn)證;
舉例:
from selenium import webdriver
from PIL import Image
import time
import pytesseract
#獲取驗(yàn)證碼截圖
def test1():
#打開谷歌瀏覽器
browser = webdriver.Chrome()
#打開首頁
browser.get("http://localhost:8080/jpress/user/register")
browser.maximize_window()
#獲取驗(yàn)證碼圖片
t = time.time()
picture_name_1 = str(t) + '.png'
browser.save_screenshot(picture_name_1)
ce = browser.find_element_by_id("captchaimg")
#獲取位置信息
print(ce.location)
left = ce.location['x']
top = ce.location['y']
right = ce.size['width'] + left
height = ce.size['height'] + top
#扣圖
im = Image.open(picture_name_1)
img = im.crop((left,top,right,height))
#保存為第二章圖片
t = time.time()
picture_name_2 = str(t) + '.png'
img.save(picture_name_2)
browser.close()
#得到截圖中的字符串
def test2():
#引入pytesseract方法識(shí)別圖片中的驗(yàn)證碼
picture_name_2 = 'test.png'
image_1 = Image.open(picture_name_2)
str = pytesseract.image_to_string(image_1)
#輸出字符串
print(str)
2、通過第三方平臺(tái),AI算法識(shí)別:https://www.showapi.com/apiGateway/view/184?skuid=5f8e59a76e3607c363634c7e
5、完成用戶注冊功能測試用例(這點(diǎn)就直接編寫測試用例,可以初始創(chuàng)建一個(gè)basic基礎(chǔ)模塊,用于封裝用例,也為后期使用框架重構(gòu)做準(zhǔn)備)
6、pytest框架進(jìn)行測試用例重構(gòu):簡單靈活,支持參數(shù)化,可以支持簡單的單元測試以及復(fù)雜的功能測試,具有豐富的第三方插件,集成selenium,集成html生成測試報(bào)告;
編寫規(guī)則:
測試文件以test開頭(以test結(jié)尾也可以)
測試類以test開頭,并且不能帶有init方法
測試函數(shù)以test開頭
斷言使用基本的assert就可以
控制臺(tái)參數(shù)信息:-v---用于顯示每個(gè)測試函數(shù)的執(zhí)行結(jié)果
-s---用于顯示測試函數(shù)中print()函數(shù)輸出
-q---只顯示整體測試結(jié)果
標(biāo)記:可以標(biāo)記用例或者函數(shù)哪些執(zhí)行哪些不執(zhí)行;
1、pytest查找策略:默認(rèn)情況下pytest會(huì)遞歸查找以test開頭或結(jié)尾的測試腳本,并執(zhí)行文件內(nèi)以test開始或結(jié)束的函數(shù)或方法;
2、標(biāo)記測試函數(shù):由于某種原因,我們想執(zhí)行指定的函數(shù)用例,可以通過標(biāo)記進(jìn)行編寫;
1、顯示指定函數(shù)名,通過::標(biāo)記:
控制臺(tái)輸入:pytest test01.py :: test01
2、使用模糊匹配,-k參數(shù)進(jìn)行標(biāo)識(shí)
控制臺(tái)輸入:pytest -k add(模糊查詢的字段) test01.py
參數(shù)化設(shè)置:可以同時(shí)運(yùn)行多個(gè)數(shù)據(jù)的測試:pytest.mark.parametrize
舉例:
import pytest
# 列表
data = ['123', '456']
@pytest.mark.parametrize('pwd', data)
def test1(pwd):
print(pwd)
# 元組
data2 = [
(1, 2, 3), # 或者[1, 2,3]
(4, 5, 6) # 或者[4, 5,6]
]
@pytest.mark.parametrize('a, b, c', data2)
def test2(a, b, c):
print(a, b, c)
# 字典
data3 = (
{
'user': 1,
'pwd': 2
},
{
'user': 3,
'pwd': 4
}
)
@pytest.mark.parametrize('dic', data3)
def test3(dic):
print(dic)
data_1 = [
pytest.param(1, 2, 3, id="(a+b):pass"), # id的值可以自定義, 只要方便理解每個(gè)用例是干什么的即可
pytest.param(4, 5, 10, id="(a+b):fail")
]
def add(a, b):
return a + b
class TestParametrize(object):
@pytest.mark.parametrize('a, b, expect', data_1)
def test_parametrize_1(self, a, b, expect):
assert add(a, b) == expect
if __name__ == '__main__':
pytest.main(['-sv', 'test3.py'])
7、pytest fixture:使用fixture實(shí)現(xiàn)用例之間的一個(gè)調(diào)用;
在函數(shù)上加一個(gè)裝飾器:@pytest.fixture()
fixture不能以test開頭,與用例區(qū)分開,fixture有返回值,沒有得話默認(rèn)返回none;
調(diào)用fixture得返回值,就是直接把fixture得函數(shù)名當(dāng)作變量名;
示例:
import pytest
@pytest.fixture()
def init():
print('init...')
return 1
def test1(init):
print('test1')
def test2(init):
print('test2')
if __name__ == '__main__':
pytest.main(['-s', '04 pytest Fixture.py']
8、pytest中setup與teardown:每次用例開始和結(jié)束都執(zhí)行一次,可以之啟動(dòng)一次瀏覽器執(zhí)行多個(gè)用例;
"""
模塊級別:(setup_module/teardown_module)開始于模塊的始末,全局的
函數(shù)級別:(setup_function/teardown_function)只對函數(shù)的用例生效,不在類中
類級別:(setup_class/teardown_class)只在類中前后運(yùn)行一次(在類中,需要使用裝飾器@classmethod)
方法級別:(setup_method/teardown_method)開始于方法始末(在類中)
類里面的:(setup/teardown)運(yùn)行在調(diào)用方法的前后
所有級別名稱必須寫對
"""
import pytest
print("=========模塊級別==========")
def setup_module():
print("setup_module")
def teardown_module():
print("teardown_module")
def test():
print("test")
print("=========函數(shù)級別==========")
def setup_function():
print("setup_function")
def teardown_function():
print("teardown_function")
def test01():
print("test01")
print("=========類級別==========")
class TestCase01(object):
@classmethod
def setup_class(cls):
print("setup_class")
@classmethod
def teardown_class(cls):
print("teardown_class")
def test03(self):
print("test03")
if __name__ == '__main__':
pytest.main('-sv','test07.py')
9、生成測試報(bào)告:
安裝allure-pytest:pip install allure-pytest
電腦本地安裝allure,配置環(huán)境變量
舉例:
import allure
import pytest
@pytest.fixture(scope="session")
def login():
print("用例先登錄")
@allure.step("步驟1:點(diǎn)xxx")
def step_1():
print("111")
@allure.step("步驟2:點(diǎn)xxx")
def step_2():
print("222")
@allure.feature("編輯頁面")
class TestEditPage():
'''編輯頁面'''
@allure.story("這是一個(gè)xxx的用例")
def test_1(self, login):
'''用例描述:先登錄,再去執(zhí)行xxx'''
step_1()
step_2()
print("xxx")
@allure.story("打開a頁面")
def test_2(self, login):
'''用例描述:先登錄,再去執(zhí)行yyy'''
print("yyy")
if __name__ == '__main__':
# 注意生成測試報(bào)告 必須在命令行執(zhí)行
#1、pytest --alluredir ./reports testcase/pytest/test6.py (目錄一定找對)
#2、 allure serve reports
pytest.main(['--alluredir', './reports', 'test08.py'])
10、進(jìn)行重構(gòu):
類中繼承object;
setup方法改為pytest setup;
報(bào)告使用pytest插件;
斷言延用python自帶得斷言;
使用pytest解決用例之間依賴關(guān)系:安裝dependency:pip install pytest-dependency
使用時(shí)在需要依賴得用例上加入裝飾器:@pytest.mark.dependency(name='xxxx')
11、selenium讀取數(shù)據(jù)庫數(shù)據(jù):
安裝mysqlclient
獲得數(shù)據(jù)庫連接
查詢數(shù)據(jù)
實(shí)例:
import MySQLdb
import pytest
conn = MySQLdb.connect(
user='root',
passwd='123456',
host='localhost',
port=3306,
db='testing_db'
)
def get_data():
query_sql = 'select id,username,pwd from user_tb'
lst = []
try:
cursor = conn.cursor()
cursor.execute(query_sql)
r = cursor.fetchall()
for x in r:
u = (x[0], x[1], x[2])
lst.append(u)
return lst
finally:
cursor.close()
conn.close()
@pytest.mark.parametrize('id, name, pwd', get_data())
def test1(id, name, pwd):
print(id, name, pwd)
if __name__ == '__main__':
pytest.main(['-sv'])