程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

第十八:第一個Python+Selenium自動化測試實戰項目(粗糙)

編輯:Python

一.前言

1.項目是針對我們公司內部系統的測試,只能內部網絡訪問,外部網絡無法訪問

2.問:

2.1.外部網絡無法訪問,代碼也無法運行,那還看這個項目有啥用。

2.2.如何學習本項目。

2.3.如何學習自動化測試(Python+Selenium)。

3.答:

3.1.其實代碼並不重要,希望大家完完整整的看完這個項目後,自己會有思路有想法,學會這個項目的框架結構和設計思想,把這些能應用到自己的項目中,那麼目的就達到了(項目中涉及到的一些公共方法是可以單獨運行的,大家可以拿來執行用到自己的項目中)。

3.2.首先希望大家帶著目標來學習這個項目:

a.項目的目錄結構(每個目錄中存放什麼東西)。

b.項目如何使用框架(本項目使用的是unittest框架)。

c.設計模式是如何應用在本項目中的(本項目應用page object設計模式)。

3.個人而言

3.1.如果沒有任何的編程基礎,建議先學習一門編程語言,包括環境的搭建,自己動手寫代碼,遇到問題多想多琢磨,這樣一定會加深自己的印象。如果有一定的編程基礎那麼直接看看Python的基礎語法和selenium就ok。

3.2.自己動手搭個框架,手寫一個實戰的項目,這時候你會發現你還有好多東西不會,那麼線路就來了,哪裡不會就去學哪裡,邊學邊寫,直到你的項目完成,再次回味就會發現你會了好多,當然不會的東西更多了因為你的思路慢慢的擴寬了,你會想到無人值守,集成等等的想法。

3.3.可以參加培訓機構的培訓,說實話現在的培訓機構越來越多,個人認為有些機構的老師確實是沒什麼水准的,因為他們教的是基礎沒有太多的拔高內容,但是有一點是好了,你可以很系統的學習一系列的自動化知識。

二.項目簡介

1.項目名稱:**公司電子零售會員系統

2.項目目的:實現電子零售會員系統項目自動化測試執行

3.項目版本:v1.0

三.項目目錄

Retail_TestPro
docs# 存放項目的相關文檔 
01測試計劃
02測試大綱
03測試用例
04測試報告
05測試進度
06技術文檔
07測試申請
package# 存放第三方插件
HTMLTestRunner.py
retail
config
__init__.py
conf.py# 讀配置文件獲取項目跟目錄路徑 並獲取所有欲使用的目錄文件的路徑
config.ini# 存放項目跟目錄的路徑
data
TestData
__init__.py
elementDate.xlsx# 存放項目中所有的元素信息及測試數據
mail_receiver.txt# 存放郵件的接受者信息
report# 測試報告
image
Fail# 存放用例執行失敗時的截圖
Pass# 存放用例執行成功時的截圖
Log# 存放用例執行過程中的log信息
TestReport# 存放測試用例執行完成後生成的測試報告
test_case# 測試用例信息
models # 存放一些公共方法
doconfini.py# 讀配置文件
doexcel.py# 讀excel文件
driver.py# 存放driver
log.py# 生成log
myunittest.py# 繼承unittest.Testcase
sendmail.py# 發送郵件
strhandle.py# 字符串處理
Tcinfo.py# 測試用例基本信息
Testreport.py# 測試報告
page_obj# 測試模塊
Activerule_page.py
Base_page.py
Company_page.py
Createrule_page.py
Memberquery_page.py
Modifypw_page.py
Pointquery_page.py
ActiveRuleTc.py
CompanyQueryTc.py
CreateRuleTc.py
LoginTc.py
MemberQueryTc.py
ModifyPwTc.py
PointQueryTc.py
runTc.py# 執行測試用例 

四.項目環境

1.python 36
2.pip insatll selenium
3.PyCharm 2017.2.4
4.Windows 10 10.0
5.HTMLTestRunner.py

五.項目框架

1.unittest單元測試框架
2.pageobject 設計模式
3.UI對象庫思想

六.項目設計

1.一個模塊(被測項目的頁面)對應一個py文件及一個測試類(測試文件)
2.每一個測試頁面(系統的頁面)中存儲頁面元素及此頁面中涉及到的功能
3.每一個用例組合在一個測試類裡面生成一個py文件

七.項目目標

1.在寫自動化測試項目的時候一定要想好腳本都要哪些功能,頁面元素頻繁改動的時候是否需要大批量的修改腳本,及測試不同數據時是否也要修改腳本,那麼能想到這些我初始目標差不多就可以。

1.1.生成測試用例執行結果報告
1.2.生成測試用例執行日志
1.3.用例執行失敗或者執行完成後自動發送郵件報告
1.4. 用例執行失敗或者成功時截取圖片
1.5.數據驅動(讀取測試數據,減少腳本維護成本)

八.項目代碼

config.ini

# 存放項目跟路徑
[project]
project_path = G:\Petrochina_Retail_Test_Project

conf.py

import os
import sys
from retail.test_case.models.doconfIni import DoConfIni
# 獲取當前路徑
currPath= \
os.path.split(os.path.realpath(__file__))[0]
print(currPath)
# 讀配置文件獲取項目路徑
readConfig = \
DoConfIni()
print(readConfig)
proPath = \
readConfig.getConfValue(os.path.join(currPath,'config.ini'),'project','project_path')
print(proPath)
# 獲取日志路徑
logPath= \
os.path.join(proPath,'retail','report','Log')
print(logPath)
# 測試用例路徑
tcPath = \
os.path.join(proPath,'retail','test_case')
print(tcPath)
# 獲取報告路徑
reportPath= \
os.path.join(proPath,'retail','report','TestReport')
print(reportPath)
# 獲取測試數據路徑
dataPath= \
os.path.join(proPath,'retail','data','TestData')
print(dataPath)
# 保存截圖路徑
# 錯誤截圖
failImagePath = os.path.join(proPath, 'retail', 'report', 'image','fail')
print(failImagePath)
# 成功截圖
passImagePath = os.path.join(proPath, 'retail', 'report', 'image','pass')
print(passImagePath)
# 被調函數名稱
funcName = sys._getframe().f_code.co_name
print(funcName)
# 被調函數所在行號
funcNo = sys._getframe().f_back.f_lineno
print(funcNo)
# 被調函數所在文件名稱
funcFile= sys._getframe().f_code.co_filename
print(funcFile)

2.elementData.xlsx # 存放所有的測試數據及元素

3.mail_receiver.txt# 存放郵件接收者的賬號 , 可以添加多個賬號以‘,’號分割

**@qq.com

4.公共方法models下面的文件方法

doconfini.py

import logging
import configparser
from retail.config.conf import *
from retail.test_case.models.log import Logger
log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
class DoConfIni(object):
def __init__(self):
""" :param filename: """
self.cf = configparser.ConfigParser()
# 從ini文件中讀數據
def getConfValue(self,filename,section,name):
""" :param config: :param name: :return: """
try:
self.cf.read(filename)
value = self.cf.get(section,name)
except Exception as e:
log.logger.exception('read file [%s] for [%s] failed , did not get the value' %(filename,section))
raise e
else:
log.logger.info('read excel value [%s] successed! ' %value)
return value
# 向ini文件中寫數據
def writeConfValue(self,filename, section, name, value):
""" :param section: section :param name: value name :param value: value :return: none """
try:
self.cf.add_section(section)
self.cf.set(section, name, value)
self.cf.write(open(filename, 'w'))
except Exception :
log.logger.exception('section %s has been exist!' %section)
raise configparser.DuplicateSectionError(section)
else:
log.logger.info('write section'+section+'with value '+value+' successed!')
if __name__ == '__main__':
file_path = currPath
print(file_path)
read_config = DoConfIni()
value = read_config.getConfValue(os.path.join(currPath,'config.ini'),'project','project_path')
print(value)
read_config.writeConfValue(os.path.join(currPath,'config.ini'),'tesesection', 'name', 'hello word')

doexcel.py

import xlrd
import os
import logging
from retail.config import conf
from retail.test_case.models.log import Logger
log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
class ReadExcel(object):
def __init__(self,fileName='elementDate.xlsx',sheetName='elementsInfo'):
""" :param fileName: :param sheetName: """
try:
self.dataFile = os.path.join(conf.dataPath, fileName)
self.workBook = xlrd.open_workbook(self.dataFile)
self.sheetName = self.workBook.sheet_by_name(sheetName)
except Exception:
log.logger.exception('init class ReadExcel fail', exc_info=True)
raise
else:
log.logger.info('initing class ReadExcel')
# 讀excel中的數據
def readExcel(self,rownum,colnum):
""" :param rownum: :param colnum: :return: """
try:
value = self.sheetName.cell(rownum,colnum).value
except Exception:
log.logger.exception('read value from excel file fail', exc_info=True)
raise
else:
log.logger.info('reading value [%s] from excel file [%s] completed' %(value, self.dataFile))
return value
if __name__ == '__main__':
cellValue = ReadExcel().readExcel(1,3)
print((cellValue))

log.py

import logging
import time
class Logger(object):
def __init__(self,logger, CmdLevel=logging.INFO, FileLevel=logging.INFO):
""" :param logger: :param CmdLevel: :param FileLevel: :return: """
self.logger = logging.getLogger(logger)
self.logger.setLevel(logging.DEBUG) # 設置日志輸出的默認級別
# 日志輸出格式
fmt = logging.Formatter('%(asctime)s - %(filename)s:[%(lineno)s] - [%(levelname)s] - %(message)s')
# 日志文件名稱
#self.LogFileName = os.path.join(conf.log_path, "{0}.log".format(time.strftime("%Y-%m-%d")))# %H_%M_%S
currTime = time.strftime("%Y-%m-%d")
self.LogFileName = r'D:\Petrochina_Retail_Test_Project\retail\report\Log\log'+currTime+'.log'
# 設置控制台輸出
#sh = logging.StreamHandler()
#sh.setFormatter(fmt)
#sh.setLevel(CmdLevel)# 日志級別
# 設置文件輸出
fh = logging.FileHandler(self.LogFileName)
fh.setFormatter(fmt)
fh.setLevel(FileLevel) # 日志級別
#self.logger.addHandler(sh)
self.logger.addHandler(fh)
def debug(self, message):
""" :param message: :return: """
self.logger.debug(message)
def info(self,message):
""" :param message: :return: """
self.logger.info(message)
def warn(self,message):
""" :param message: :return: """
self.logger.warning(message)
def error(self,message):
""" :param message: :return: """
self.logger.error(message)
def criti(self,message):
""" :param message: :return: """
self.logger.critical(message)
if __name__ == '__main__':
logger = Logger("fox",CmdLevel=logging.DEBUG, FileLevel=logging.DEBUG)
logger.logger.debug("debug")
#ERROR,log日志 error
logger.logger.log(logging.ERROR,'%(module)s %(info)s',{
'module':'log日志','info':'error'})

sendmail.py

import smtplib
from email.mime.text import MIMEText
from email.header import Header
import os
from retail.config import conf
from retail.test_case.models.log import Logger
log = Logger(__name__)
# 郵件發送接口
class SendMail(object):
'''郵件配置信息'''
def __init__(self,
receiver,
subject='Retail 系統測試報告',
server='smtp.qq.com',
fromuser='[email protected]',
frompassword='gifhhsbgqyovbhhc',
sender='[email protected]'):
""" :param receiver: :param subject: :param server: :param fromuser: :param frompassword: :param sender: :return: """
self._server = server
self._fromuser = fromuser
self._frompassword = frompassword
self._sender = sender
self._receiver = receiver
self._subject = subject
def sendEmail(self, fileName):
""" :param fileName: :return: """
# 打開報告文件讀取文件內容
try:
f = open(os.path.join(conf.reportPath, fileName), 'rb')
fileMsg = f.read()
except Exception:
log.logger.exception('open or read file [%s] failed,No such file or directory: %s' %(fileName, conf.reportPath))
log.logger.info('open and read file [%s] successed!' %fileName)
else:
f.close()
# 郵件主題
subject = 'Python test report'
# 郵件設置
msg = MIMEText(fileMsg, 'html', 'utf-8')
msg['subject'] = Header(subject, 'utf-8')
msg['from'] = self._sender
# 連接服務器,登錄服務器,發送郵件
try:
smtp = smtplib.SMTP()
smtp.connect(self._server)
smtp.login(self._fromuser, self._frompassword)
except Exception:
log.logger.exception('connect [%s] server failed or username and password incorrect!' %smtp)
else:
log.logger.info('email server [%s] login success!' %smtp)
try:
smtp.sendmail(self._sender, self._receiver, msg.as_string())
except Exception:
log.logger.exception('send email failed!')
else:
log.logger.info('send email successed!')
# 從文件中讀取郵件接收人信息
def getReceiverInfo(fileName):
''' :param filename: 讀取接收郵件人信息 :return: 接收郵件人信息 '''
try:
openFile = open(os.path.join(conf.dataPath, fileName))
except Exception:
log.logger.exception('open or read file [%s] failed,No such file or directory: %s' %(fileName, conf.dataPath))
else:
log.logger.info('open file [%s] successed!' %fileName)
for line in openFile:
msg = [i.strip() for i in line.split(',')]
log.logger.info('reading [%s] and got receiver value is [%s]' %(fileName, msg))
return msg
if __name__ == '__main__':
readMsg = getReceiverInfo('mail_receiver.txt')
#readMsg = SendMail.getReceiverInfo('mail_receiver.txt')
sendmail = SendMail(readMsg)
sendmail.sendEmail('2018-09-21 17_44_04.html')

strhandle.py

import logging
from retail.test_case.models.log import Logger
log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
def strhandle(str):
""" :param str: :return: """
# 初始化字符、數字、空格、特殊字符的計數
try:
lowerCase = 0
upperCase = 0
number = 0
other = 0
for stritem in str:
# 如果在字符串中有小寫字母,那麼小寫字母的數量+1
if stritem.islower():
lowerCase += 1
# 如果在字符串中有數字,那麼數字的數量+1
elif stritem.isdigit():
number += 1
# 大寫字母
elif stritem.isupper():
upperCase +=1
# 如果在字符串中有空格,那麼空格的數量+1
else:
other += 1
return lowerCase, upperCase, number, other
except Exception as e:
log.logger.exception('string handle error , please check!', exc_info=True)
raise e
if __name__=='__main__':
list = ['qwert','erwer']
lowercase, uppercase, number, other = strhandle(list[0])
print (u"該字符串中的小寫字母有:%d" %lowercase)
print (u"該字符串中的大寫寫字母有:%d" %uppercase)
print (u"該字符串中的數字有:%d" %number)
print (u"該字符串中的特殊字符有:%d" %other)

testreport.py

import time
import logging
import unittest
from BeautifulReport import BeautifulReport
import HTMLTestRunner
from retail.config import conf
from retail.test_case.models.log import Logger
log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
# 用HTMLTestRunner 實現的測試報告
def testreport():
currTime = time.strftime('%Y-%m-%d %H_%M_%S')
fileName = conf.reportPath + r'\report' + currTime + '.html'
try:
fp = open(fileName, 'wb')
except Exception :
log.logger.exception('[%s] open error cause Failed to generate test report' %fileName)
else:
runner = HTMLTestRunner.HTMLTestRunner\
(stream=fp, title=u'Retail sys測試報告',
description=u'處理器:Intel(R) Core(TM) ''i5-6200U CPU @ 2030GHz 2.40 GHz 'u'內存:8G 系統類型: 64位 版本: windows 10 家庭中文版')
log.logger.info('successed to generate test report [%s]' %fileName)
return runner, fp, fileName
def addTc(TCpath = conf.tcPath, rule = '*TC.py'):
""" :param TCpath: 測試用例存放路徑 :param rule: 匹配的測試用例文件 :return: 測試套件 """
discover = unittest.defaultTestLoader.discover(TCpath, rule)
return discover
# 用BeautifulReport模塊實現測試報告
def runTc(discover):
""" :param discover: 測試套件 :return: """
currTime = time.strftime('%Y-%m-%d %H_%M_%S')
fileName = currTime+'.html'
try:
result = BeautifulReport(discover)
result.report(filename=fileName, description='測試報告', log_path=conf.reportPath)
except Exception:
log.logger.exception('Failed to generate test report', exc_info=True)
else:
log.logger.info('successed to generate test report [%s]' % fileName)
return fileName
if __name__ == '__main__':
testreport()
suite = addTc(rule = '*TC.py')
runTc(suite)

driver.py

from selenium import webdriver
import logging
import sys
from retail.test_case.models.log import Logger
log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
class WDriver(object):
def fireFoxDriver(self):
try:
self.driver = webdriver.Firefox()
except Exception as e:
log.logger.exception('FireFoxDriverServer.exe executable needs to be in PATH. Please download!', exc_info=True)
raise e
else:
log.logger.info('%s:found the Firefox driver [%s] successed !' %(sys._getframe().f_code.co_name,self.driver))
return self.driver
# chrom driver
def chromeDriver(self):
try:
#option = webdriver.ChromeOptions() # 實現不打開浏覽器 執行web自動化測試腳本
#option.add_argument('headless')#
#self.driver = webdriver.Chrome(chrome_options=option)
self.driver = webdriver.Chrome()
except Exception as e:
log.logger.exception('ChromeDriverServer.exe executable needs to be in PATH. Please download!',exc_info=True)
raise e
else:
log.logger.info('%s:found the chrome driver [%s] successed !' % (sys._getframe().f_code.co_name, self.driver))
return self.driver
# Ie driver
def ieDriver(self):
try:
self.driver = webdriver.Ie()
except Exception as e:
log.logger.exception('IEDriverServer.exe executable needs to be in PATH. Please download!',exc_info=True)
raise e
else:
log.logger.info('%s:found the IE driver [%s] successed !' % (sys._getframe().f_code.co_name, self.driver))
return self.driver
if __name__ == '__main__':
WDrive=WDriver()
WDrive.fireFoxDriver()

myunittest.py

from retail.test_case.models.driver import WDriver
import logging
import unittest
from retail.test_case.page_obj.login_page import LoginPage
from retail.test_case.models.log import Logger
from selenium import webdriver
log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
class MyunitTest(unittest.TestCase):
@classmethod
# 一個測試類(文件)執行一次打開浏覽器, 節約每個用例打開一次浏覽器的時間
def setUpClass(cls):
#cls.driver = WDriver().fireFoxDriver()
cls.driver = WDriver().chromeDriver()
cls.driver.maximize_window()
log.logger.info('opened the browser successed!')
def setUp(self):
self.login = LoginPage(self.driver)
self.login.open()
log.logger.info('************************starting run test cases************************')
def tearDown(self):
self.driver.refresh()
log.logger.info('************************test case run completed************************')
@classmethod
def tearDownClass(cls):
cls.driver.quit()
log.logger.info('quit the browser success!')
if __name__ == '__main__':
unittest.main()

九.需要的所有公共方法都編寫完了, 後期再需要別的方法可以加。下面就開始編寫測試用例,由於使用的是PageObject模式,那麼需要設計一個basepage頁面,所有的頁面或者說模塊全部繼承這個basepage,basepage主要編寫所有頁面的公共方法。

base_page.py

from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import os
import logging
import sys
from retail.test_case.models.log import Logger
from retail.config import conf
from retail.test_case.models.doexcel import ReadExcel
# 存儲系統所有的元素數據
eleData = ReadExcel()
# 登錄模塊測試數據
testLoginData = ReadExcel('elementDate.xlsx', 'userNamePw')
# 修改密碼模塊測試數據
modifyPwData = ReadExcel('elementDate.xlsx', 'modifyPw')
queryData = ReadExcel('elementDate.xlsx', 'queryData')
log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
class BasePage(object):
"""主菜單"""
menuList = \
[(By.LINK_TEXT, eleData.readExcel(7, 3)), # 權限管理
(By.LINK_TEXT, eleData.readExcel(8, 3)), # 會員檔案
(By.LINK_TEXT, eleData.readExcel(9, 3)), # 積分消費查詢
(By.LINK_TEXT, eleData.readExcel(10, 3)), # 功能演示
(By.LINK_TEXT, eleData.readExcel(11, 3)), # 待辦工作
(By.LINK_TEXT, eleData.readExcel(12, 3)), # 報表
(By.LINK_TEXT, eleData.readExcel(13, 3)), # 積分規則/活動查詢
(By.LINK_TEXT, eleData.readExcel(14, 3))] # 積分規則/活動申請
def __init__(self, driver,url='http://11.11.164.134:9081/rmms/modules/ep.rmms.portal/login/login.jsp'):
self.driver = driver
self.base_url = url
def _open(self,url):
try:
self.driver.get(url)
self.driver.implicitly_wait(10)
except Exception as e:
log.logger.exception(e, exc_info=True)
raise ValueError('%s address access error, please check!' %url)
else:
log.logger.info('%s is accessing address %s at line[46]' %(sys._getframe().f_code.co_name,url))
def open(self):
self._open(self.base_url)
log.logger.info('%s loading successed!' %self.base_url)
return self.base_url
# *loc 代表任意數量的位置參數
def findElement(self, *loc):
"""查找單一元素"""
try:
WebDriverWait(self.driver,10).until(EC.visibility_of_element_located(loc))
#log.logger.info('The page of %s had already find the element %s'%(self,loc))
#return self.driver.find_element(*loc)
except Exception as e:
log.logger.exception('finding element timeout!, details' ,exc_info=True)
raise e
else:
log.logger.info('The page of %s had already find the element %s' % (self, loc))
return self.driver.find_element(*loc)
def findElements(self, *loc):
"""查找一組元素"""
try:
WebDriverWait(self.driver,10).until(EC.visibility_of_element_located(loc))
#log.logger.info('The page of %s had already find the element %s' % (self, loc))
#return self.driver.find_elements(*loc)
except Exception as e:
log.logger.exception('finding element timeout!, details', exc_info=True)
raise e
else:
log.logger.info('The page of %s had already find the element %s' % (self, loc))
return self.driver.find_elements(*loc)
def inputValue(self, inputBox, value):
"""後期修改其他頁面直接調用這個函數"""
inputB = self.findElement(*inputBox)
try:
inputB.clear()
inputB.send_keys(value)
except Exception as e:
log.logger.exception('typing value error!', exc_info=True)
raise e
else:
log.logger.info('inputValue:[%s] is receiveing value [%s]' % (inputBox, value))
# 獲取元素數據
def getValue(self, *loc):
element = self.findElement(*loc)
try:
value = element.text
#return value
except Exception:
#element = self.find_element_re(*loc) # 2018.09.21 for log
value = element.get_attribute('value')
log.logger.info('reading the element [%s] value [%s]' % (loc, value))
return value
except:
log.logger.exception('read value failed', exc_info=True)
raise Exception
else:
log.logger.info('reading the element [%s] value [%s]' % (loc,value))
return value
def getValues(self, *loc):
value_list = []
try:
for element in self.findElements(*loc):
value = element.text
value_list.append(value)
except Exception as e:
log.logger.exception('read value failed', exc_info=True)
raise e
else:
log.logger.info('reading the element [%s] value [%s]'% (loc,value_list))
return value_list
# 執行js腳本
def jScript(self,src):
try:
self.driver.excute_script(src)
except Exception as e:
log.logger.exception('execute js script [%s] failed ' %src)
raise e
else:
log.logger.info('execute js script [%s] successed ' %src)
# 判斷元素是否存在
def isElementExist(self, element):
try:
WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located(element))
except:
#log.logger.exception('The element [%s] not exist', exc_info=True)
return False
else:
#log.logger.info('The element [%s] have existed!' %element)
return True
# 截圖
def saveScreenShot(self, filename):
list_value = []
list = filename.split('.')
for value in list:
list_value.append(value)
if list_value[1] == 'png' or list_value[1] == 'jpg' or list_value[1] == 'PNG' or list_value[1] == 'JPG':
if 'fail' in list_value[0].split('_'):
try:
self.driver.save_screenshot(os.path.join(conf.failImagePath, filename))
except Exception:
log.logger.exception('save screenshot failed !', exc_info=True)
else:
log.logger.info('the file [%s] save screenshot successed under [%s]' % (filename, conf.failImagePath))
elif 'pass' in list_value[0]:
try:
self.driver.save_screenshot(os.path.join(conf.passImagePath, filename))
except Exception:
log.logger.exception('save screenshot failed !', exc_info=True)
else:
log.logger.info('the file [%s] save screenshot successed under [%s]' % (filename, conf.passImagePath))
else:
log.logger.info('save screenshot failed due to [%s] format incorrect' %filename)
else:
log.logger.info('the file name of [%s] format incorrect cause save screenshot failed, please check!' % filename)
# 接受錯誤提示框
def accept(self, *loc):
self.findElement(*loc).click()
log.logger.info('closed the error information fram successed!')
if __name__ == '__main__':
pass

1.登錄頁面
login_page.py

from selenium.webdriver.common.by import By
import logging
import sys
from retail.test_case.page_obj.base_page import BasePage, eleData, testLoginData
from retail.test_case.models.log import Logger
log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
class LoginPage(BasePage):
"""用戶名,密碼,登錄按鈕,保存信息,錯誤提示"""
userNameEle = (By.ID, eleData.readExcel(1, 3))
passWordEle = (By.ID, eleData.readExcel(2, 3))
loginBtnEle = (By.ID, eleData.readExcel(3, 3))
saveInfoEle = (By.NAME, eleData.readExcel(4, 3))
errorMessage = (By.ID, eleData.readExcel(5, 3))
quitBtn = (By.ID, eleData.readExcel(6, 3))
# 用戶名和密碼
unpwData = \
[[testLoginData.readExcel(1, 0), testLoginData.readExcel(1, 1)], # 正確的用戶名和正確的密碼
[testLoginData.readExcel(2, 0), testLoginData.readExcel(2, 1)], # 錯誤的用戶名和正確的密碼
[testLoginData.readExcel(3, 0), testLoginData.readExcel(3, 1)], # 空的用戶名和正確的密碼
[testLoginData.readExcel(4, 0), testLoginData.readExcel(4, 1)], # 錯誤的用戶名和錯誤的密碼
[testLoginData.readExcel(5, 0), testLoginData.readExcel(5, 1)], # 正確的用戶名和空密碼
[testLoginData.readExcel(6, 0), testLoginData.readExcel(6, 1)], # 正確的用戶名和錯誤的密碼
[testLoginData.readExcel(7, 0), testLoginData.readExcel(7, 1)]] # 空用戶名和空密碼
# 登錄按鈕
def clickLoginBtn(self):
element = self.findElement(*self.loginBtnEle)
element.click()
log.logger.info('%s ,logining....!' % sys._getframe().f_code.co_name)
# 登錄失敗時提示
def getFailedText(self):
info = self.findElement(*self.errorMessage).text
log.logger.info('login failed : %s' %info)
return info
# 登錄失敗時彈出的alert
def handleAlert(self):
try:
alert = self.driver.switch_to_alert()
text = alert.text
alert.accept()
except Exception:
log.logger.exception('handle alert failed, please check the details' ,exc_info=True)
raise
else:
log.logger.info('login failed ,%s handle alert successed alert info: %s!' %(sys._getframe().f_code.co_name, text))
return text
# 統一登錄函數
def loginFunc(self, username='rmln', password='[email protected]#'):
self.inputValue(self.userNameEle, username)
self.inputValue(self.passWordEle, password)
self.clickLoginBtn()
# 清空輸入框數據
def clearValue(self, element):
empty = self.findElement(*element)
empty.clear()
log.logger.info('emptying value.......')
# 退出
def quit(self):
self.findElement(*self.quitBtn).click()
log.logger.info('quit')
if __name__ == '__main__':
pass

2.登錄測試用例
LoginTc.py

import unittest
import time
import logging
import sys
from retail.test_case.models.myunittest import MyunitTest
from retail.test_case.models.log import Logger
log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
class Login_TC(MyunitTest):
"""登錄模塊測試用例"""
def test_login_success_correct_username_password(self):
"""用戶名正確,密碼正確,登錄成功"""
self.login.loginFunc()
# 獲取當前的url地址
currUrl = self.driver.current_url
try:
self.assertIn('main', currUrl, 'main not in current url!')
except Exception:
self.login.saveScreenShot('correct_username_password_fail.png')
raise
else:
self.login.saveScreenShot('correct_username_password_pass.png')
log.logger.info('%s->run completed! please check the test report' % (sys._getframe().f_code.co_name))
def test_login_failed_incorrect_username(self):
"""用戶名錯誤,密碼正確,登錄失敗"""
self.login.loginFunc(self.login.unpwData[1][0], self.login.unpwData[1][1])
failText = self.login.getFailedText()
self.assertEqual(u'輸入的用戶名或密碼錯誤,請重新輸入!', failText, u'提示信息錯誤')
log.logger.info('%s->run completed! please check the test report' % (sys._getframe().f_code.co_name))
def test_login_failed_incorrect_password(self):
"""用戶名正確,密碼錯誤,登錄失敗"""
self.login.loginFunc(self.login.unpwData[5][0], self.login.unpwData[5][1])
failText = self.login.getFailedText()
self.assertEqual(u'輸入的用戶名或密碼錯誤,請重新輸入!', failText, u'提示信息錯誤')
log.logger.info('%s->run completed! please check the test report' % (sys._getframe().f_code.co_name))
def test_login_failed_username_password_blank(self):
"""用戶名為空,密碼為空,登錄失敗"""
self.login.loginFunc(self.login.unpwData[6][0], self.login.unpwData[6][1])
failText = self.login.handleAlert() # 獲取alert的提示信息
self.assertEqual(u'請填寫用戶名', failText, u'提示信息錯誤')
log.logger.info('%s->run completed! please check the test report' % (sys._getframe().f_code.co_name))
def test_login_failed_password_blank(self):
"""用戶名正確,密碼為空,登錄失敗"""
self.login.loginFunc(self.login.unpwData[4][0], self.login.unpwData[4][1])
failText = self.login.handleAlert() # 獲取alert的提示信息
self.assertEqual(u'請填寫用戶密碼', failText, u'提示信息錯誤')
log.logger.info('%s->run completed! please check the test report' % (sys._getframe().f_code.co_name))
def test_login_failed_unpw_incorrect(self):
"""用戶名錯誤,密碼錯誤,登錄失敗"""
self.login.loginFunc(self.login.unpwData[3][0], self.login.unpwData[4][0])
failText = self.login.getFailedText()
self.assertEqual (u'輸入的用戶名或密碼錯誤,請重新輸入!', failText, 'failed')
log.logger.info('%s->run completed! please check the test report' % (sys._getframe().f_code.co_name))
def test_login(self):
"""循環測試登錄功能"""
for listitem in self.login.unpwData:
self.login.inputValue(self.login.userNameEle,listitem[0])
time.sleep(2)
self.login.inputValue(self.login.passWordEle,listitem[1])
time.sleep(2)
self.login.clickLoginBtn()
time.sleep(2)
if listitem[0] =='rmln' and listitem[1] == '[email protected]#':
currUrl = self.driver.current_url
self.assertIn ('main' , currUrl)
self.login.quit()
elif listitem[0] == 'rmln' and listitem[1] != '[email protected]#':
if listitem[1] == '':
failText = self.login.handleAlert() # 獲取alert的提示信息
self.assertEqual(u'請填寫用戶密碼', failText, u'提示信息錯誤')
else:
failText = self.login.getFailedText()
self.assertEqual(u'輸入的用戶名或密碼錯誤,請重新輸入!', failText, u'提示信息錯誤')
elif listitem[0] != 'rmln' and listitem[1] == '[email protected]#':
if listitem[0]=='':
failText = self.login.handleAlert() # 獲取alert的提示信息
self.assertEqual(u'請填寫用戶名', failText, u'提示信息錯誤')
else:
failText = self.login.getFailedText()
self.assertEqual(u'輸入的用戶名或密碼錯誤,請重新輸入!', failText, u'提示信息錯誤')
elif listitem[0] == listitem[1] == '':
failText = self.login.handleAlert() # 獲取alert的提示信息
self.assertEqual(u'請填寫用戶名', failText, '提示信息錯誤')
else:
failText = self.login.getFailedText()
self.assertEqual(u'輸入的用戶名或密碼錯誤,請重新輸入!', failText, u'提示信息錯誤')
log.logger.info('%s->run completed! please check the test report' % (sys._getframe().f_code.co_name))
if __name__ == '__main__':
unittest.main()

3.修改密碼頁面
modifypw_page.py

import logging
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from retail.test_case.page_obj.base_page import BasePage, eleData, modifyPwData
from retail.test_case.models.log import Logger
log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
class PrimaryMenu(BasePage):
"""密碼數據"""
pwdList = \
[[modifyPwData.readExcel(1, 0), modifyPwData.readExcel(1, 1), modifyPwData.readExcel(1, 2)],
[modifyPwData.readExcel(2, 0), modifyPwData.readExcel(2, 1), modifyPwData.readExcel(2, 2)],
[modifyPwData.readExcel(3, 0), modifyPwData.readExcel(3, 1), modifyPwData.readExcel(3, 2)],
[modifyPwData.readExcel(4, 0), modifyPwData.readExcel(4, 1), modifyPwData.readExcel(4, 2)],
[modifyPwData.readExcel(5, 0), modifyPwData.readExcel(5, 1), modifyPwData.readExcel(5, 2)]]
"""權限管理下拉菜單"""
menuPersonal = (By.LINK_TEXT, eleData.readExcel(15, 3))
menuModifyPwd = (By.LINK_TEXT, eleData.readExcel(16, 3))
"""密碼修改"""
oldPwd = (By.ID, eleData.readExcel(17, 3))
newPwd = (By.ID, eleData.readExcel(18, 3))
commitPwd = (By.ID, eleData.readExcel(19, 3))
"""錯誤提示框及確定"""
errMessage = (By.XPATH, eleData.readExcel(20, 3))
closeBtn = (By.CSS_SELECTOR, eleData.readExcel(21, 3))
"""密碼說明"""
readMe = (By.ID, eleData.readExcel(22, 3))
"""保存"""
saveBtn = (By.XPATH, eleData.readExcel(23, 3))
# 主菜單
def findMenu(self,*menuList):
return self.findElement(*menuList)
# 舊密碼輸入框
def inputOldPw(self, oldPwd=''):
try:
self.findElement(*self.oldPwd).clear()
self.findElement(*self.oldPwd).send_keys(oldPwd)
except Exception:
log.logger.exception('input Pw [%s] for oldPw [%s] fail' %(oldPwd, self.oldPwd))
raise
else:
log.logger.info('inputing Pw [%s] for oldPw [%s] ' % (oldPwd, self.oldPwd))
# 新密碼輸入框
def inputNewPw(self, newPwd=''):
try:
self.findElement(*self.newPwd).clear()
self.findElement(*self.newPwd).send_keys(newPwd)
except Exception:
log.logger.exception('input Pw [%s] for newPw [%s] fail' % (newPwd, self.newPwd))
raise
else:
log.logger.info('inputing Pw [%s] for newPw [%s] ' % (newPwd, self.newPwd))
# 確認密碼輸入框
def inputConfirmPw(self, confirmPwd=''):
try:
self.findElement(*self.commitPwd).clear()
self.findElement(*self.commitPwd).send_keys(confirmPwd)
except Exception:
log.logger.exception('input Pw [%s] for commitPw [%s] fail' %(confirmPwd, self.commitPwd))
raise
else:
log.logger.info('inputing Pw [%s] for commitPw [%s] ' %(confirmPwd, self.commitPwd))
# 保存
def saveButton(self):
try:
self.driver.implicitly_wait(5)
clickbutton = self.findElement(*self.saveBtn)
time.sleep(1)
clickbutton.click()
except Exception:
log.logger.exception('click save button fail')
raise
else:
log.logger.info('clciking the button')
# 修改密碼功能菜單
def modifyPwMenu(self):
try:
self.findElement(*self.menuList[0]).click()
self.findElement(*self.menuPersonal).click()
self.findElement(*self.menuModifyPwd).click()
except Exception:
log.logger.exception('not found menu [%s]-[%s]-[%s]' %(self.menuList[0], self.menuPersonal, self.menuModifyPwd))
raise
else:
log.logger.info('finding menu [%s]-[%s]-[%s]' %(self.menuList[0], self.menuPersonal, self.menuModifyPwd))
self.driver.implicitly_wait(2)
# 修改密碼
def modifyPw(self, list):
try:
self.inputOldPw(list[0])
self.inputNewPw(list[1])
self.inputConfirmPw(list[2])
self.saveButton()
except Exception:
log.logger.exception('input oldpw/newpw/commitpw [%s]/[%s]/[%s] fail' %(list[0], list[1], list[2]))
raise
else:
log.logger.info('modifing pw [%s]/[%s]/[%s]' %(list[0], list[1], list[2]))
# 錯誤提示框
def errorDialog(self, commit_btn = (By.ID,'unieap_form_Button_1_unieap_input')):
""" :type commit_btn: 元祖 """
try:
messages_frame = self.findElement(*self.errMessage)
text = messages_frame.text
element = self.findElement(*commit_btn)
time.sleep(2)
action = ActionChains(self.driver)
action.move_to_element(element).perform()
time.sleep(2)
element.click()
# 釋放鼠標
action.reset_actions()
except Exception:
log.logger.exception('close errMsgFram [%s] or get text [%s]fail' %(self.errMessage))
raise
else:
log.logger.info('close errMsgFram [%s] and get text [%s] success' %(self.errMessage, text))
return text
# 關閉提示框
def closeErrMsg(self, element):
try:
ele = self.findElement(*element)
action = ActionChains(self.driver)
action.move_to_element(ele).perform()
time.sleep(2)
ele.click()
action.reset_actions()
except Exception:
log.logger.exception('close the err msg ifram fail', exc_info=True)
raise
else:
log.logger.info('closing the err msg ifram success!')
if __name__ == '__main__':
pass

4.修改密碼測試用例
ModifyPw.py

import time
from retail.test_case.models.myunittest import MyunitTest
from retail.test_case.page_obj.modifypw_page import PrimaryMenu
from retail.test_case.models.strhandle import strhandle
class ModifyPw_TC(MyunitTest):
"""權限管理/個人設置/密碼修改模塊測試用例"""
def test_menu_is_display(self):
"""主菜單校驗"""
self.login.loginFunc()
menu = PrimaryMenu(self.driver)
time.sleep(4)
num = 0
# 循環遍歷並斷言菜單是否正確
for menu_item in menu.menuList:
self.assertEqual(menu.menuList[num][1],(menu.findMenu(*menu_item).text),u'菜單不存在')
num=num+1
def test_modify_password_len(self):
"""舊密碼非空,新密碼長度小於4位,確認密碼非空,修改密碼失敗,彈窗提示"""
self.login.loginFunc()
menu = PrimaryMenu(self.driver)
# 查找修改密碼頁面
menu.modifyPwMenu()
# 修改密碼
menu.modifyPw(menu.pwdList[0])
text = menu.errorDialog(menu.closeBtn)
# 密碼長度不滿足時斷言提示信息
self.assertIn(u'密碼長度至少 4 位!', text, u'提示信息錯誤')
def test_modify_password_strebgth(self):
"""舊密碼非空,新密碼長度大於4且強度不夠,確認密碼非空,修改密碼失敗,彈窗提示"""
self.login.loginFunc()
menu = PrimaryMenu(self.driver)
menu.modifyPwMenu() # 查找修改密碼頁面
menu.modifyPw(menu.pwdList[1]) # 修改密碼
text = menu.errorDialog(menu.closeBtn)
# 密碼強度不滿足時斷言提示信息
self.assertIn(u'密碼強度不夠,請重新輸入密碼!', text, u' 密碼強度不夠,請重新輸入密碼!')
def test_modify_password_incorrect(self):
"""舊密碼不正確非空,新密碼等於確認密碼且滿足條件,修改密碼失敗,彈窗提示"""
self.login.loginFunc()
menu = PrimaryMenu(self.driver)
menu.modifyPwMenu() # 查找修改密碼頁面
menu.modifyPw(menu.pwdList[2]) # 修改密碼
text = menu.errorDialog(menu.closeBtn)
# 新密碼和確認碼不同時斷言提示信息
self.assertIn(u'舊密碼輸入錯誤!', text, u'舊密碼輸入錯誤!')
def test_modify_password_difference(self):
"""舊密碼非空,新密碼不等於確認密碼且新密碼滿足條件,修改密碼失敗,彈窗提示"""
self.login.loginFunc()
menu = PrimaryMenu(self.driver)
# 查找修改密碼頁面
menu.modifyPwMenu()
# 修改密碼
menu.modifyPw(menu.pwdList[3])
text = menu.errorDialog(menu.closeBtn)
# 新密碼和確認碼不同時斷言提示信息
self.assertIn(u'兩次輸入的新密碼不同!', text, u'兩次輸入的新密碼不同!')
def test_modify_password_all_blank(self):
"""舊密碼,新密碼,確認密碼任意為空,修改密碼失敗,彈窗提示"""
self.login.loginFunc()
menu = PrimaryMenu(self.driver)
menu.modifyPwMenu() # 查找修改密碼頁面
menu.modifyPw(menu.pwdList[4]) # 修改密碼
text = menu.errorDialog(menu.closeBtn)
# 所有密碼均為空時斷言提示信息
self.assertIn(u'該輸入項的值不能為空!', text, u' 該輸入項的值不能為空!')
def test_modify_password(self):
"""循環校驗提示信息"""
self.login.loginFunc()
menu = PrimaryMenu(self.driver)
# 查找修改密碼頁面
menu.modifyPwMenu()
error_list = []
for list in range(len(menu.pwdList)):
menu.modifyPw(menu.pwdList[list])
if menu.isElementExist(menu.errMessage):
# 這裡只判斷是否有提示框彈出,如有說明修改失敗,沒有或者其他提示框默認為修改成功
text = menu.errorDialog(menu.closeBtn)
error_list.append(text)
else:
self.assertTrue(menu.isElementExist(*menu.errMessage), 'error fram not exist, please open bug')
self.assertEqual(u'密碼長度至少 4 位!',error_list[0],'log infomation error!')
self.assertEqual(u'密碼強度不夠,請重新輸入密碼!', error_list[1], 'log infomation error!')
self.assertEqual(u'舊密碼輸入錯誤!', error_list[2], 'log infomation error!')
self.assertEqual(u'兩次輸入的新密碼不同!', error_list[3], 'log infomation error!')
self.assertEqual(u'該輸入項的值不能為空!', error_list[4], 'log infomation error!')
def test_modifypw(self):
"""循環測試修改密碼功能"""
# 登錄
self.login.loginFunc()
menu = PrimaryMenu(self.driver)
# 查找修改密碼頁面
menu.modifyPwMenu()
for item in menu.pwdList:
menu.modifyPw(item)
# 如果存在提示框 再斷言提示信息是否正確
if menu.isElementExist(menu.errMessage):
# 新密碼長度校驗
if item[0] != '' and len(item[1]) < 4 and item[2] !='':
text = menu.errorDialog(menu.closeBtn)
try:
self.assertEqual(u'密碼長度至少 4 位!',text,'the message incorrect!')
except Exception:
menu.saveScreenShot(u'fail_密碼長度.png')
raise
# 新密碼強度校驗 ['a', 'qwert', 'qwert']
elif item[0] != '' and len(item[1]) >= 4 and item[2] !='':
lowercase, uppercase, number, other=strhandle(item[1])
# 小寫 大寫
if lowercase > 0 and uppercase > 0 and number == 0 and other == 0:
text = menu.errorDialog(menu.closeBtn)
self.assertIn(u'密碼強度不夠,請重新輸入密碼!', text, u' 密碼強度不夠,請重新輸入密碼!')
# 大寫 特殊字符
elif uppercase > 0 and other > 0 and number == 0 and lowercase == 0:
text = menu.errorDialog(menu.closeBtn)
self.assertIn(u'密碼強度不夠,請重新輸入密碼!', text, u' 密碼強度不夠,請重新輸入密碼!')
# 小寫 特殊字符
elif lowercase >0 and other > 0 and number == 0 and uppercase == 0:
text = menu.errorDialog(menu.closeBtn)
self.assertIn(u'密碼強度不夠,請重新輸入密碼!', text, u' 密碼強度不夠,請重新輸入密碼!')
# 大寫 數字
elif lowercase == 0 and other == 0 and number > 0 and uppercase > 0:
text = menu.errorDialog(menu.closeBtn)
self.assertIn(u'密碼強度不夠,請重新輸入密碼!', text, u'密碼強度不夠,請重新輸入密碼!')
# 小寫 數字
elif lowercase > 0 and other == 0 and number > 0 and uppercase == 0:
text = menu.errorDialog(menu.closeBtn)
self.assertIn(u'密碼強度不夠,請重新輸入密碼!', text, u'密碼強度不夠,請重新輸入密碼!')
elif lowercase > 0 and other == 0 and number == 0 and uppercase == 0:
text = menu.errorDialog(menu.closeBtn)
self.assertIn(u'密碼強度不夠,請重新輸入密碼!', text, u'密碼強度不夠,請重新輸入密碼!')
elif lowercase == 0 and other > 0 and number == 0 and uppercase == 0:
text = menu.errorDialog(menu.closeBtn)
self.assertIn(u'密碼強度不夠,請重新輸入密碼!', text, u'密碼強度不夠,請重新輸入密碼!')
elif lowercase == 0 and other == 0 and number > 0 and uppercase == 0:
text = menu.errorDialog(menu.closeBtn)
self.assertIn(u'密碼強度不夠,請重新輸入密碼!', text, u'密碼強度不夠,請重新輸入密碼!')
elif lowercase == 0 and other == 0 and number == 0 and uppercase > 0:
text = menu.errorDialog(menu.closeBtn)
self.assertIn(u'密碼強度不夠,請重新輸入密碼!', text, u'密碼強度不夠,請重新輸入密碼!')
# >= 4
elif item[0] != '[email protected]#' and item[1] == item[2]:
lowercase, uppercase, number, other = strhandle(item[1])
if (lowercase > 0 and uppercase > 0 and number > 0) or (
lowercase > 0 and uppercase > 0 and other > 0) or (
number > 0 and other > 0 and lowercase > 0) or (
number > 0 and other > 0 and uppercase > 0):
text = menu.errorDialog(menu.closeBtn)
# 新密碼和確認碼不同時斷言提示信息
self.assertIn(u'舊密碼輸入錯誤!', text, u'舊密碼輸入錯誤!')
# and item[1] >= 4
elif item[0] == '[email protected]#$' and item[1] != item[2]:
lowercase, uppercase, number, other = strhandle(item[1])
if (lowercase > 0 and uppercase > 0 and number > 0) or (
lowercase > 0 and uppercase > 0 and other > 0) or (
number > 0 and other > 0 and lowercase > 0) or (
number > 0 and other > 0 and uppercase > 0):
text = menu.errorDialog(menu.closeBtn)
self.assertIn(u'兩次輸入的新密碼不同!', text, u'兩次輸入的新密碼不同!')
else:
print('test value incorrect! please check it')
# 輸入項為空校驗
elif item[0] == '' or item[1] =='' or item[2] =='':
text = menu.errorDialog(menu.closeBtn)
# 所有密碼均為空時斷言提示信息
self.assertIn(u'該輸入項的值不能為空!', text, u'該輸入項的值不能為空!')
else:
self.assertTrue(menu.isElementExist(menu.errMessage), 'error fram not exist, please check the test value or file bug')
if __name__=='__main__':
pass

5.會員檔案查詢頁面
memberquery_page.py

from retail.test_case.page_obj.base_page import queryData
import time
from selenium.webdriver.common.by import By
import logging
import sys
from retail.test_case.page_obj.modifypw_page import PrimaryMenu, eleData
from retail.test_case.models.log import Logger
log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
class MemberQuery(PrimaryMenu):
# 測試數據: 會員編碼, 會員姓名, 手機號碼
valuesList = [queryData.readExcel(1, 1), int(queryData.readExcel(2, 1)), queryData.readExcel(3, 1)]
# 會員檔案下拉菜單
memberMenu = (By.LINK_TEXT, eleData.readExcel(24, 3))
# 會員查詢頁面的3個列表(查詢條件,會員信息明細,積分變化明細)
uiElements = (By.XPATH, eleData.readExcel(25, 3))
# 會員類型
memberTypeBtn = (By.ID, eleData.readExcel(26, 3))
# 會員類型下拉選項
memberTypeNum = [(By.XPATH, eleData.readExcel(27, 3)),
(By.XPATH, eleData.readExcel(28, 3)),
(By.XPATH, eleData.readExcel(29, 3))]
# 會員級別
memberLevelBtn = (By.ID, eleData.readExcel(30, 3))
# 會員級別下拉選項
memberLevelNum = [(By.XPATH, eleData.readExcel(31, 3)),
(By.XPATH, eleData.readExcel(32, 3)),
(By.XPATH, eleData.readExcel(33, 3)),
(By.XPATH, eleData.readExcel(34, 3))]
# 會員編號,會員姓名,手機號碼
memberNumNamePhone = [(By.ID, eleData.readExcel(35, 3)),
(By.ID, eleData.readExcel(36, 3)),
(By.ID, eleData.readExcel(37, 3))]
# 查詢異常提示框
# 查詢失敗彈出的錯誤提示框
qFailerr = (By.XPATH, eleData.readExcel(38, 3))
confirmBtn = (By.XPATH, eleData.readExcel(39, 3))
# 查詢與重置
queryResetBtn = [(By.ID, eleData.readExcel(40, 3)),
(By.ID, eleData.readExcel(41, 3))]
# 點擊會員類型
def selectMemberType(self):
try:
self.findElement(*self.memberTypeBtn).click()
self.driver.implicitly_wait(2)
except Exception:
log.logger.exception('selecting member type fail ')
raise
else:
log.logger.info('---selecting member type ')
# 點擊會員級別
def selectMemberLevel(self):
try:
self.findElement(*self.memberLevelBtn).click()
self.driver.implicitly_wait(2)
except Exception:
log.logger.exception('selecting member level fail ')
raise
else:
log.logger.info('---selecting member level ')
# 查找會員檔案查詢菜單
def memberQueryMenu(self):
self.findElement(*self.menuList[1]).click()
self.findElement(*self.memberMenu).click()
time.sleep(4)
log.logger.info('page [%s] :found the menu [%s] and [%s]' % (
sys._getframe().f_code.co_name, self.menuList[1], self.memberMenu))
# 會員類型/會員級別下拉選項
def memberTypeLevelOption(self, *xpathList):
try:
member_type_level = self.findElement(*xpathList)
text = member_type_level.text
except Exception:
log.logger.exception('get element member type/level item text fail', exc_info=True)
raise
else:
log.logger.info('get element [%s] member type/level item text [%s] fail' % (xpathList, text))
return text, member_type_level
# 點擊查詢和重置按鈕
def cQueryResetBtn(self, *queryResetBtn):
try:
self.findElement(*queryResetBtn).click()
except Exception:
log.logger.exception('query/reset button not click', exc_info=True)
raise
else:
log.logger.info('clicking query/reset button ')
# 輸入查詢條件
def iQueryCondition(self, numNamePhone, value):
number_name_phone = self.findElement(*numNamePhone)
try:
number_name_phone.clear()
number_name_phone.send_keys(value)
except Exception:
log.logger.exception('input value error', exc_info=True)
raise
else:
log.logger.info('[%s] is typing value [%s] ' % (numNamePhone, value))
# 獲取條件輸入框的內容
def getInputboxValue(self, *memberNumNamePhone):
try:
get_member_number_name_phone_text = self.findElement(*memberNumNamePhone)
text = get_member_number_name_phone_text.get_attribute('value')
except Exception:
log.logger.exception('get value of element fail', exc_info=True)
raise
else:
log.logger.info('get value [%s] of element [%s] success' % (memberNumNamePhone, text))
return text
# 重置功能的重寫
def reset(self):
try:
self.findElement(*self.memberNumNamePhone[0]).clear()
self.findElement(*self.memberNumNamePhone[1]).clear()
self.findElement(*self.memberNumNamePhone[2]).clear()
except Exception:
log.logger.exception('reset fail', exc_info=True)
raise
else:
log.logger.info('reset [%s]-[%s]-[%s] success' % (
self.memberNumNamePhone[0], self.memberNumNamePhone[1], self.memberNumNamePhone[2]))
if __name__ == '__main__':
pass

6.會員檔案查詢用例
MemberQueryTc.py

import random
import time
from selenium.webdriver.common.action_chains import ActionChains
from retail.test_case.models.myunittest import MyunitTest
from retail.test_case.page_obj.memberquery_page import MemberQuery
class MemberQuery_TC(MyunitTest):
"""會員檔案查詢模塊測試用例"""
#@unittest.skip('dont run the test case')
def test_member_check_ui(self):
"""會員檔案查詢頁面顯示正確"""
# 實例化會員查詢頁面
menu = MemberQuery(self.driver)
self.login.loginFunc()
# 查找會員檔案查詢菜單
menu.memberQueryMenu()
elements = menu.findElements(*menu.uiElements)
ele_list = []
for eles in elements:
if eles.text !='':
ele_list.append(eles.text)
self.assertEqual(u'查詢條件', ele_list[0])
self.assertEqual(u'會員信息明細', ele_list[1])
self.assertEqual(u'積分變化明細', ele_list[2])
def test_member_type(self):
"""會員類型下拉列表項正確"""
# 實例化會員查詢頁面
menu = MemberQuery(self.driver)
# 登錄
self.login.loginFunc()
# 查找會員檔案查詢菜單
menu.memberQueryMenu()
menu.selectMemberType()
list_type = []
# 循環遍歷會員類型下拉列表
for member_type in menu.memberTypeNum:
text, memeber_type_level = menu.memberTypeLevelOption(*member_type)
list_type.append(text)
self.assertEqual(u'個人會員', list_type[0])
self.assertEqual(u'企業會員', list_type[1])
self.assertEqual(u'其它', list_type[2])
def test_member_level(self):
"""會員級別下拉列表項正確"""
# 實例化會員查詢頁面
menu = MemberQuery(self.driver)
# 登錄
self.login.loginFunc()
# 查找會員檔案查詢菜單
menu.memberQueryMenu()
menu.selectMemberLevel()
list_level = []
# 循環遍歷會員級別下拉列表
for member_level in menu.memberLevelNum:
text, memeber_type_level = menu.memberTypeLevelOption(*member_level)
list_level.append(text)
self.assertEqual(u'標准會員', list_level[0])
self.assertEqual(u'黃金會員', list_level[1])
self.assertEqual(u'鉑金會員', list_level[2])
self.assertEqual(u'鑽石會員', list_level[3])
# ............................................................................................#
# 對頁面的條件進行組合後單擊查詢按鈕。這是一個大數據量的操作,因此不對返回數據做校驗,只看本次組合的條件在頁面是否可正常使用。
# 如果查詢失敗,系統會有彈出框提示失敗原因,這個應該很好理解的。
# 我們抓取這個框是否在一定的時間內出現,如果出現則判定本次查詢失敗,記錄用例結果。
# ............................................................................................#
def test_member_query_failed(self):
"""默認條件查詢成功"""
# 實例化會員檔案查詢頁面
menu = MemberQuery(self.driver)
# 登錄
self.login.loginFunc()
# 找到會員查詢頁面
menu.memberQueryMenu()
# 點擊[查詢]
menu.cQueryResetBtn(*menu.queryResetBtn[0])
# 斷言錯誤提示框
flag = menu.isElementExist(menu.qFailerr)
# flag為false時,斷言成功, 無提示框,說明默認查詢成功
self.assertFalse(flag, msg=u'查詢失敗')
def test_alone_query_1(self):
"""按會員編號,會員姓名,手機號碼單一條件查詢"""
# 實例化會員檔案查詢頁面
menu = MemberQuery(self.driver)
# 登錄
self.login.loginFunc()
# 找到會員檔案查詢頁面
menu.memberQueryMenu()
for num_name_phone in menu.memberNumNamePhone:
# 重置
menu.reset()
for value in menu.valuesList:
menu.iQueryCondition(num_name_phone,value)
# 點擊[查詢]
menu.cQueryResetBtn(*menu.queryResetBtn[0])
time.sleep(3)
flag = menu.isElementExist(menu.qFailerr)
if flag:
self.assertTrue(flag, u'提示框不存在,查詢成功')
menu.accept(*menu.confirmBtn)
else:
self.assertFalse(flag, u'提示框存在,查詢失敗')
def test_alone_query_2(self):
"""按會員類型單一查詢"""
# 實例化會員檔案查詢頁面
menu = MemberQuery(self.driver)
# 登錄
self.login.loginFunc()
# 找到會員檔案查詢頁面
menu.memberQueryMenu()
for me_type in menu.memberTypeNum:
# 點擊[會員類型]
menu.selectMemberType()
# 遍歷每一個下拉選項
text, member_type_level = menu.memberTypeLevelOption(*me_type)
# 鼠標移動到下拉選項上
ActionChains(self.driver).move_to_element(member_type_level).perform()
# 選中下拉選項
member_type_level.click()
# 點擊[查詢]
menu.cQueryResetBtn(*menu.queryResetBtn[0])
time.sleep(3)
# 判斷查詢成功
flag = menu.isElementExist(menu.qFailerr)
self.assertFalse(flag, u'提示框存在,查詢失敗')
def test_alone_query_3(self):
"""按會員級別單一查詢"""
# 實例化會員檔案查詢頁面
menu = MemberQuery(self.driver)
# 登錄
self.login.loginFunc()
# 找到會員檔案查詢頁面
menu.memberQueryMenu()
for me_level in menu.memberLevelNum:
# 點擊[會員級別]
menu.selectMemberLevel()
# 遍歷每一個下拉選項
text, member_level = menu.memberTypeLevelOption(*me_level)
# 鼠標移動到下拉選項上
ActionChains(self.driver).move_to_element(member_level).perform()
# 選中下拉選項
member_level.click()
# 點擊[查詢]
menu.cQueryResetBtn(*menu.queryResetBtn[0])
time.sleep(3)
# 判斷查詢成功
flag = menu.isElementExist(menu.qFailerr)
self.assertFalse(flag, u'提示框存在,查詢成功')
def test_reset(self):
"""重置功能校驗"""
# 實例化會員檔案查詢頁面
menu = MemberQuery(self.driver)
# 登錄
self.login.loginFunc()
# 找到會員檔案查詢頁面
menu.memberQueryMenu()
# 3個條件輸入框隨機輸入數據
for inputBox in menu.memberNumNamePhone:
menu.iQueryCondition(inputBox,random.choice(menu.valuesList))
# 會員類型下拉列表中隨機選擇一項
menu.selectMemberType()
text_type, member_type = menu.memberTypeLevelOption(*(random.choice(menu.memberTypeNum)))
# 鼠標移動到下拉選項上
ActionChains(self.driver).move_to_element(member_type).perform()
member_type.click()
#menu.selectMemberLevel()
#text_level, member_level = menu.memberTypeLevelOption(*(random.choice(menu.member_level_num)))
#ActionChains(self.driver).move_to_element(member_level).perform()
#member_level.click()
# 點擊【重置】
menu.cQueryResetBtn(*menu.queryResetBtn[1])
# 獲取前3個輸入框的內容
text_list = []
for input_box in menu.memberNumNamePhone:
text = menu.getInputboxValue(*input_box)
text_list.append(text)
# 獲取會員類型
type_type_text = menu.getInputboxValue(*menu.memberTypeBtn)
text_list.append(type_type_text)
#type_level_text = menu.getInputboxValue(*menu.member_level_btn)
#text_list.append(type_level_text)
# 斷言每一個條件框是否為空 為空就通過
for get_attr in text_list:
self.assertEqual('',get_attr)
if __name__ == '__main__':
pass

7.執行測試用例

7.1.from BeautifulReport import BeautifulReport 這個報告需要網上找一下(很多類似的測試報告源碼,不一定非使用本案例中的報告模板)。

RunTc.py

import unittest
import time
from BeautifulReport import BeautifulReport
from retail.config.conf import *
from retail.test_case.models.testreport import testreport
if __name__ == '__main__':
#currTime = time.strftime('%Y-%m-%d %H_%M_%S')
#filename = currTime + '.html'
# 第一種測試報告
#test_suite = unittest.defaultTestLoader.discover(tcPath, pattern='*Tc.py')
#result = BeautifulReport(test_suite)
#result.report(filename= filename, description='test report', log_path=reportPath)
# 第二種測試報告
runner, fp, fileName = testreport()
test_suite = unittest.defaultTestLoader.discover(tcPath, pattern='LoginTc.py')
runner.run(test_suite)
fp.close()

十.報告展示

1.截圖:創建規則失敗時截圖。

2.截圖:登錄成功截圖。

3.用例執行日志:一部分日志記錄。

4.測試報告

十一.總結

1.看到結果還是挺有成就感的,郵件的截圖我沒發,因為我是內網不知道什麼原因郵件服務器連接不上,但是使用外網單獨測試郵件發送是沒什麼問題的!

2.就寫這麼多吧,其他頁面的用例設計思路都是一樣的,因為所有的用例彼此都是獨立的,所以多與少都不影響! 要源碼的同學可以訪問我的github自己下載吧!


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved