自動化回歸測試實戰
目前遇到的項目模塊自動化已經完成的差不多了,俗話說:"好記性不如爛筆頭",所以最近整理了項目自動化中遇到的問題以及解決方法。
先說一下,實際當前項目已經使用RF框架完成了一版自動化,但是實際執行該腳本需花費幾天的時間;考慮到時間成本,所以后面想改用其他框架提高執行效率。經過多方對比和項目實際情況,最后確定seldom對當前項目比較實用,所以以下是基於seldom進行的自動化測試。
seldom的優勢:
- 提供更加簡單API編寫自動化測試
- 提供腳手架,快速生成自動化測試項目
- 全局啟動和關閉瀏覽器,減少瀏覽器的啟動次數
- 提供支持多種數據文件參數化
- 支持用例失敗/錯誤重跑
- 支持生成HTML/XML測試報告
- 支持HTTP接口測試 (v 2.0)
其他需要了解此框架的其他操作請前往https://github.com/SeldomQA/seldom/tree/master/docs
項目思路
-
自動化中一般是使用url地址來進行基本的操作,這樣也便於下次直接切換基礎url地址進行項目自動化回歸驗證,所以這里是把url地址使用conf配置文件單獨存放,便於統一管理和維護,比如采購申請和采購申請添加頁面存放在beta.conf中,使用時則讀取beta.conf配置文件中的信息。這里使用ConfigParse讀取配置文件,操作代碼如下
# beta.conf配置文件內容如下
[beta]
# 登錄url
beta_url = http://172.17.1.10/test
username = yy
password = 123456
audit_username = yyadmin
aduit_username01 = yyadmin001
aduit_username02 = yyadmin002
aduit_username03 = yyadmin003
aduit_username04 = yyadmin004
aduit_username05 = yyadmin005
aduit_username06 = yyadmin006
audit_username07 = yyadmin095
# 采購品目添加url
Procurement_item_url=/a/purchase/catalog/form
# 采購目錄列表
pe_list=/a/purchase/catalog/list
# 讀取配置文件操作
os.chdir("E:\\rcm_seldom\\test_dir")
# 讀取配置文件中的url
config = ConfigParser()
# 傳入讀取文件的地址,encoding文件編碼格式,中文必須
with codecs.open('beta.conf', 'r', encoding='utf-8') as f:
config.read_file(f)
# 返回所有信息
#secs = config.sections()
#beta = config.items("beta", "beta")
url = config.get("beta", "beta_url")
print(url)
before_temp_url = config.get("beta", "Procurement_item_url")
# audit_username
audit_username =config.get("beta", "audit_username")
password = config.get("beta", "password")
beta_apply_list_temp = config.get("beta", "pe_list")
before_url = url + before_temp_url
beta_apply_list = url + beta_apply_list_temp
print(before_url)
print(beta_apply_list)
- seldom框架中使用了po模式,將page頁面元素定位方法和測試用例隔離,如before_apply_common_page.py,代碼如下:
# before_apply_common_page.py
# coding=utf-8
from poium import Page, PageElement
class BeforeApplyCommonPage(Page):
# 選擇預算指標按鈕
before_budget_target_button = PageElement(xpath="//input[@id='budgetName']")
# 選中預算指標
before_budget_target_selected = PageElement(xpath="//table[@id='dataGrid']//tr[3]//td[2]//input[1]")
# 確認預算指標
before_budget_target_confirm = PageElement(xpath="//a[@class='layui-layer-btn0']")
# 是否簽訂合同-否
before_budget_sign_no = PageElement(xpath="//input[@id='contractFlag2']")
# 是否簽訂合同-是
before_budget_sign_is = PageElement(xpath="//input[@id='contractFlag1']")
# 申請理由
before_budget_remarks = PageElement(xpath="//textarea[@id='applyReason']")
# 申請金額
before_budget_amount = PageElement(xpath="//input[@id='applyAmount0']")
# 事前申請附件點擊按鈕
before_budget_file_button = PageElement(xpath="//form[@id='inputForm']//li[2]//a[1]")
# 事前申請附件添加按鈕
before_budget_file_submit = PageElement(xpath="//div[contains(@id,'rt_rt')]")
# 事前申請上傳附件
# 事前申請查詢收縮按鈕
before_budget_shrink_button = PageElement(xpath="//i[@id='shrinkIco']")
# 事前申請提交
before_budget_submit = PageElement(xpath="//body/form/div/input[2]")
# 事前申請暫存&確認審核&查詢確認按鈕
before_budget_save= PageElement(xpath="//input[@id='btnSubmit']")
# 附件預覽
before_budget_preview = PageElement(xpath="//a[contains(@id,'view')]")
# 事前申請刪除按鈕
# before_budget_modify_button = PageElement(link_text="修改")
before_budget_modify_button = PageElement(xpath="//table[@id='dataGrid_rightfrozen']//tbody[1]//tr[2]//td[1]//a[1]")
# 事前申請刪除按鈕
# before_budget_del_button = PageElement(link_text="刪除")
before_budget_del_button = PageElement(xpath="///table[@id='dataGrid_rightfrozen']//tbody[1]//tr[2]//td[1]//a[2]")
# 事前申請確認刪除&確認審核
before_budget_del_confirm = PageElement(xpath="//a[@class='layui-layer-btn0']")
# 事前申請查詢申請事由
before_budget_apply_reason = PageElement(xpath="//input[@id='applyReason']")
# 事前申請審核按鈕
# before_budget_audit_button = PageElement(link_text="審批")
before_budget_audit_button = PageElement(xpath="//table[@id='dataGrid_rightfrozen']//tbody[1]//tr[2]//td[1]//a[1]")
# ----------------------------136服務器頁面信息-------------------
before_is_audit_button = PageElement(xpath="//div[@id='s2id_IS_A']//span[@class='select2-chosen']")
before_is_audit = PageElement(xpath="//div[@id='select2-drop']//li[2]//div[1]")
before_is_info_button = PageElement(xpath="//div[@id='s2id_IS_B']//span[@class='select2-chosen']")
before_is_class_button = PageElement(xpath="//div[@id='s2id_IS_C']//span[@class='select2-chosen']")
而具體的測試用例則在test_before_apply_common.py文件中,此文件直寫了具體的測試用例,有保存、提交、修改、刪除以及審批常用的方法,這里頁面元素信息輸入使用了公用方法common_before_contrat,如圖
# test_before_apply_common.py
# coding=utf-8
import seldom
import time
import random
import string
import os
from seldom import Seldom
from poium import Page, PageElement, PageSelect
from faker import Faker
from configparser import ConfigParser
import codecs
import sys
from .before_apply_common_page import BeforeApplyCommonPage
# import before_apply_common_page
#存放c.py所在的絕對路徑
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(BASE_DIR)
print(BASE_DIR)
from test_poium_encapsulate import LoginTest
# 跳過測試類
@seldom.skip()
class BeforeApplyCommonTest(seldom.TestCase):
os.chdir("E:\\rcm_seldom\\test_dir")
# 讀取配置文件中的url
config = ConfigParser()
# 傳入讀取文件的地址,encoding文件編碼格式,中文必須
with codecs.open('beta.conf', 'r', encoding='utf-8') as f:
config.read_file(f)
# 返回所有信息
#secs = config.sections()
#beta = config.items("beta", "beta")
url = config.get("beta", "beta_url")
print(url)
before_temp_url = config.get("beta", "beforeApplyCommon_add")
# audit_username
audit_username =config.get("beta", "audit_username")
password = config.get("beta", "password")
beta_apply_list_temp = config.get("beta", "beforeApplyCommon_list")
before_url = url + before_temp_url
beta_apply_list = url + beta_apply_list_temp
print(before_url)
print(beta_apply_list)
def start(self):
#登錄
# login =LoginTest().login
# login()
cookie_beta = self.get_cookie('yy')
print(cookie_beta)
def common_before_contract(self):
"""設置事前申請信息,填寫所有提交審核,為合同輸入數據"""
# 事前申請添加輸入信息隨機參數
localTime = time.strftime("%Y%m%d%H%M%S", time.localtime())
salt = ''.join(random.sample(string.ascii_letters + string.digits, 8))
provider_name = salt + localTime
# num = ''.join(random.sample(string.digits, 8))
# reveive_code = num + localTime
fake = Faker(locale='zh_CN')
# provider_code = fake.random_number(digits=7, fix_len=False)
apply_amount_temp = fake.pyfloat(left_digits=3, right_digits=2, positive=True)
apply_amount = str(apply_amount_temp)
print(apply_amount)
# provider_remarks = fake.sentences()
# login =LoginTest().login
# login()
sign_login = LoginTest()
sign_login.login()
# 切換主題
sign_login.default_change_theme()
page = BeforeApplyCommonPage(Seldom.driver)
# 打開url
self.get(self.before_url)
self.sleep(3)
# 點擊預算指標信息按鈕
page.before_budget_target_button.click()
self.sleep(3)
# 進入收款方frame框架
self.switch_to_frame(xpath="//iframe[@id='layui-layer-iframe1']")
# 選中預算指標
page.before_budget_target_selected.click()
# 退出frame
self.switch_to_frame_out()
self.sleep(1)
page.before_budget_target_confirm.click()
self.sleep(1)
# 是否簽訂合同-是
page.before_budget_sign_is.click()
# 申請理由
page.before_budget_remarks = provider_name
# 申請金額
page.before_budget_amount = apply_amount
# #事前申請附件點擊按鈕信息
# page.before_budget_file_button.click()
# # 事前申請附件添加按鈕
# page.before_budget_file_submit.click()
# # 事前申請附件上傳操作
# os.system("E:\\rcm_seldom\\test_dir\\upload1.exe")
# self.sleep(3)
# # 附件預覽
# page.before_budget_preview.click()
# # 切換到第一個窗口
# advance_apply_list = self.window_handles
# print(advance_apply_list)
# self.switch_to_window('advance_apply_list[0]')
# --------------------附件上傳第二種方式----------
# filePath = r'C:\Users\admin\Postman\files\發票模塊說明文檔.doc'
# self.type(xpath='', text=filePath)
# 提交事前申請
page.before_budget_submit.click()
self.sleep(5)
# 事前申請斷言
page.before_budget_shrink_button.click()
page.before_budget_apply_reason = provider_name
page.before_budget_save.click()
self.sleep(8)
self.assertText(provider_name)
return provider_name, apply_amount
# 跳過測試類
# @seldom.skip()
def test_common_save(self):
"""設置事前申請信息,填寫所有僅保存"""
# 事前申請添加輸入信息隨機參數
localTime = time.strftime("%Y%m%d%H%M%S", time.localtime())
salt = ''.join(random.sample(string.ascii_letters + string.digits, 8))
provider_name = salt + localTime
# num = ''.join(random.sample(string.digits, 8))
# reveive_code = num + localTime
fake = Faker(locale='zh_CN')
# provider_code = fake.random_number(digits=7, fix_len=False)
apply_amount_temp = fake.pyfloat(left_digits=3, right_digits=2, positive=True)
apply_amount = str(apply_amount_temp)
print(apply_amount)
# provider_remarks = fake.sentences()
# login =LoginTest().login
# login()
sign_login = LoginTest()
sign_login.login()
# 切換主題
sign_login.default_change_theme()
page = BeforeApplyCommonPage(Seldom.driver)
# 打開url
self.get(self.before_url)
self.sleep(3)
# 點擊預算指標信息按鈕
page.before_budget_target_button.click()
self.sleep(1)
# 進入收款方frame框架
self.switch_to_frame(xpath="//iframe[@id='layui-layer-iframe1']")
# 選中預算指標
page.before_budget_target_selected.click()
# 退出frame
self.switch_to_frame_out()
self.sleep(1)
page.before_budget_target_confirm.click()
self.sleep(1)
# 是否簽訂合同-否
page.before_budget_sign_no.click()
# 申請理由
page.before_budget_remarks = provider_name
# 申請金額
page.before_budget_amount = apply_amount
# """事前申請附件上傳暫時無用,原因未知"""
# #事前申請附件點擊按鈕信息
# page.before_budget_file_button.click()
# # 事前申請附件添加按鈕
# page.before_budget_file_submit.click()
# # 事前申請附件上傳操作
# os.system("E:\\rcm_seldom\\test_dir\\upload1.exe")
# self.sleep(3)
# 保存事前申請
page.before_budget_save.click()
self.sleep(8)
# 事前申請斷言
page.before_budget_shrink_button.click()
page.before_budget_apply_reason = provider_name
page.before_budget_save.click()
self.sleep(8)
self.assertText(provider_name)
# 返回reviev_code
return provider_name, apply_amount
# 跳過測試類
# @seldom.skip()
def test_common_submit(self):
"""設置事前申請信息,填寫所有提交審核"""
# 事前申請添加輸入信息隨機參數
localTime = time.strftime("%Y%m%d%H%M%S", time.localtime())
salt = ''.join(random.sample(string.ascii_letters + string.digits, 8))
provider_name = salt + localTime
# num = ''.join(random.sample(string.digits, 8))
# reveive_code = num + localTime
fake = Faker(locale='zh_CN')
# provider_code = fake.random_number(digits=7, fix_len=False)
apply_amount_temp = fake.pyfloat(left_digits=3, right_digits=2, positive=True)
apply_amount = str(apply_amount_temp)
print(apply_amount)
# provider_remarks = fake.sentences()
login =LoginTest().login
login()
page = BeforeApplyCommonPage(Seldom.driver)
# 打開url
self.get(self.before_url)
self.sleep(3)
# 點擊預算指標信息按鈕
page.before_budget_target_button.click()
self.sleep(1)
# 進入收款方frame框架
self.switch_to_frame(xpath="//iframe[@id='layui-layer-iframe1']")
# 選中預算指標
page.before_budget_target_selected.click()
# 退出frame
self.switch_to_frame_out()
self.sleep(1)
page.before_budget_target_confirm.click()
self.sleep(3)
# 是否簽訂合同-否
page.before_budget_sign_no.click()
# 申請理由
page.before_budget_remarks = provider_name
# 申請金額
page.before_budget_amount = apply_amount
# #事前申請附件點擊按鈕信息
# page.before_budget_file_button.click()
# # 事前申請附件添加按鈕
# page.before_budget_file_submit.click()
# # 事前申請附件上傳操作
# os.system("E:\\rcm_seldom\\test_dir\\upload1.exe")
# self.sleep(3)
# # 附件預覽
# page.before_budget_preview.click()
# # 切換到第一個窗口
# advance_apply_list = self.window_handles
# print(advance_apply_list)
# self.switch_to_window('advance_apply_list[0]')
# 提交事前申請
page.before_budget_submit.click()
self.sleep(8)
# 事前申請斷言
page.before_budget_shrink_button.click()
page.before_budget_apply_reason = provider_name
page.before_budget_save.click()
self.sleep(8)
self.assertText(provider_name)
return provider_name, apply_amount
# 跳過測試類
# @seldom.skip()
def test_common_modify(self):
"""修改事前申請信息"""
# 事前申請添加輸入信息隨機參數
localTime = time.strftime("%Y%m%d%H%M%S", time.localtime())
salt = ''.join(random.sample(string.ascii_letters + string.digits, 8))
provider_name = salt + localTime
# num = ''.join(random.sample(string.digits, 8))
# reveive_code = num + localTime
fake = Faker(locale='zh_CN')
# provider_code = fake.random_number(digits=7, fix_len=False)
apply_amount_temp = fake.pyfloat(left_digits=3, right_digits=2, positive=True)
apply_amount = str(apply_amount_temp)
print(apply_amount)
""""添加事前申請信息"""
self.test_common_save()
self.sleep(3)
page = BeforeApplyCommonPage(Seldom.driver)
"""修改事前申請"""
page.before_budget_modify_button.click()
# 修改事前申請
page.before_budget_remarks.clear()
page.before_budget_remarks = provider_name
# 申請金額
# page.before_budget_amount.clear()
self.clear(xpath="//input[@id='applyAmount0']")
page.before_budget_amount = apply_amount
# 保存事前申請
page.before_budget_save.click()
self.sleep(10)
# 事前申請斷言
page.before_budget_shrink_button.click()
page.before_budget_apply_reason = provider_name
page.before_budget_save.click()
self.sleep(9)
self.assertText(provider_name)
# 跳過測試類
# @seldom.skip()
def test_common_del(self):
"""刪除事前申請操作"""
# 添加事前申請信息
apply_reason, apply_amount = self.test_common_save()
print("apply_reason是:"+ apply_reason)
print("apply_amount是:"+ apply_amount)
page = BeforeApplyCommonPage(Seldom.driver)
# 刪除事前申請
# page.before_budget_shrink_button.click()
# page.before_budget_apply_reason = apply_reason
# page.before_budget_save.click()
self.sleep(8)
page.before_budget_del_button.click()
page.before_budget_del_confirm.click()
self.sleep(8)
self.assertText(apply_reason)
# 跳過測試類
# @seldom.skip()
def test_common_audit(self):
"""事前申請審核操作"""
# 添加事前申請
apply_reason, apply_amount = self.test_common_submit()
print(type(apply_reason))
print("apply_reason是:"+ apply_reason)
print(apply_amount)
page = BeforeApplyCommonPage(Seldom.driver)
# 退出當前賬號登錄
logout = LoginTest().logout
logout()
# 審核賬號登錄
login =LoginTest()
login.account_login(self.audit_username, self.password)
# login()
# LoginTest().account_login(self.audit_username, self.password)
# 打開url
self.get(self.beta_apply_list)
self.sleep(5)
#審核操作,查詢該申請單
page.before_budget_shrink_button.click()
page.before_budget_apply_reason = apply_reason
page.before_budget_save.click()
self.sleep(5)
# 點擊審核按鈕
page.before_budget_audit_button.click()
self.sleep(6)
page.before_budget_save.click()
self.sleep(6)
page.before_budget_del_confirm.click()
self.sleep(6)
page.before_budget_shrink_button.click()
page.before_budget_apply_reason = apply_reason
page.before_budget_save.click()
self.sleep(6)
self.assertText(apply_reason)
return apply_reason, apply_amount
# 跳過測試類
# @seldom.skip()
def test_common_contract_audit(self):
"""事前申請審核操作-簽訂合同"""
# 添加事前申請
apply_reason, apply_amount = self.common_before_contract()
print(type(apply_reason))
print("apply_reason是:"+ apply_reason)
print(apply_amount)
page = BeforeApplyCommonPage(Seldom.driver)
# 退出當前賬號登錄
logout = LoginTest().logout
logout()
# 審核賬號登錄
login =LoginTest()
login.account_login(self.audit_username, self.password)
# login()
# LoginTest().account_login(self.audit_username, self.password)
# 打開url
self.get(self.beta_apply_list)
self.sleep(5)
#審核操作,查詢該申請單
page.before_budget_shrink_button.click()
page.before_budget_apply_reason = apply_reason
page.before_budget_save.click()
self.sleep(6)
# 點擊審核按鈕
page.before_budget_audit_button.click()
page.before_budget_save.click()
self.sleep(6)
page.before_budget_del_confirm.click()
self.sleep(6)
page.before_budget_shrink_button.click()
page.before_budget_apply_reason = apply_reason
page.before_budget_save.click()
self.sleep(6)
self.assertText(apply_reason)
return apply_reason, apply_amount
def end(self):
#退出
logout = LoginTest().logout
logout()
if __name__ == '__main__':
# seldom.main("test_before_apply_common.py", rerun=0)
seldom.main()
- 其他通常代碼完成后可能需要調試,seldom也支持單獨運行某個測試用例進行代碼調試,整體測試通過后seldom還可以生成一份HTML的測試報告,我們可以在代碼中將報告及時發送給需要實時追蹤的項目干系人,以便及時掌握項目的最新進展。
這里可以看一下最終生成的報告展示:
- 如果項目足夠龐大,還是建議做好文件夾分模塊,這樣便於后期維護。
總體下來,目前已使用seldom完成項目常用模塊的自動化回歸操作,項目常用代碼已全部上傳gitee上。以上就是該項目所有自動化的實戰。整體下來,最初難以抉擇的還是自動化工具的選型,一旦自動化工具確定后,余下的就是為了實現此目標。
關於自動化工具的選擇
這里稍微提下關於自動化工具的選型:
我們進行自動化操作最主要的一點是當前項目是否適用自動化,項目需求以及頁面是否經常變動,這是考慮自動化成本的一個非常重要的一點,不過對於一些固化不變的模塊,我們也可以適當考慮部分自動化,畢竟能減少我們的工作量,降低線上問題概率就解決了實際問題
另外還有兩點是需要考慮的
- 自動化框架的使用廣度,出現問題是否可以快速定位並解決
- 團隊整體的實用性,不管使用任何工具包括RobotFrameWork、python+selenium等的都需要調研當前團隊的接受以及學習成本。