前言
之前的文章說過, 要寫一篇自動化實戰的文章, 這段時間比較忙再加回家過11一直沒有更新博客,今天整理一下實戰專案的代碼共大家學習,(注:專案是針對我們公司內部系統的測驗,只能內部網路訪問,外部網路無法訪問)
問:
1.外部網路無法訪問,代碼也無法運行,那還看這個專案有啥用
2.如何學習本專案
3.如何學習自動化測驗(python+selenium)
答:
1.其實代碼并不重要,希望大家完完整整的看完這個專案后,自己會有思路有想法,學會這個專案的框架結構和設計思想,把這些能應用到自己的專案中,那么目的就達到了(專案中涉及到的一些公共方法是可以單獨運行的,大家可以拿來執行用到自己的專案中)
2.首先希望大家帶著目標來學習這個專案1. 專案的目錄結構(每個目錄中存放什么東西)2.專案如何使用框架(本專案使用的是unittest框架)3.設計模式是如何應用在本專案中的(本專案應用page object設計模式)
3.個人而言
1)如果你沒有任何的編程基礎,建議先學習一門編程語言,包括環境的搭建,自己動手寫代碼,遇到問題多想多琢磨,這樣一定會加深自己的印象,如果你有一定的編程基礎那么直接看看python的基礎語法和selenium就ok(我的自動化測驗經驗也有限,可能給不了大家太多的建議 ,當然會的越多越好 呵!)
2)自己動手搭個框架,手寫一個實戰的專案,這時候你會發現你還有好多東西不會,那么線路就來了,哪里不會就去學哪里,邊學邊寫,直到你的專案完成,再次回味就會發現你會了好多,當然不會的東西更多了因為你的思路慢慢的擴寬了,你會想到無人值守,集成等等的想法
3)可以參加培訓機構的培訓,說實話現在的培訓機構越來越多,個人認為有些機構的老師確實是沒什么水準的,因為他們教的是基礎沒有太多的拔高內容,但是有一點是好了,你可以很系統的學習一系列的自動化知識
ok 說了很多廢話,大家不要介意!直接上專案
專案簡介
專案名稱:**公司電子零售會員系統
專案目的:實作電子零售會員系統專案自動化測驗執行
專案版本: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# 存放專案中所有的元素資訊及測驗資料
Email_receiver.txt# 存放郵件的接受者資訊
Report# 測驗報告
Image
Fail# 存放用例執行失敗時的截圖
Pass# 存放用例執行成功時的截圖
Log# 存放用例執行程序中的log資訊
TestReport# 存放測驗用例執行完成后生成的測驗報告
Test_case# 測驗用例資訊
Models # 存放一些公共方法
Doconfini.py# 讀組態檔
Doexcel.py# 讀excel檔案
Driver.py# 存放driver
Log.py# 生成log
Myunit.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# 執行測驗用例

專案環境
本版
python 36
pip insatll selenium
PyCharm 2017.2.4
Windows 10 10.0
HTMLTestRunner.py
專案框架
unittest單元測驗框架
pageobject 設計模式
UI物件庫思想
專案設計
1.一個模塊(被測專案的頁面)對應一個py檔案及一個測驗類(測驗檔案)
2.每一個測驗頁面(系統的頁面)中存盤頁面元素及此頁面中涉及到的功能
3.每一個用例組合在一個測驗類里面生成一個py檔案
專案目標
我們在寫自動化測驗專案的時候一定要想好你的腳本都要哪些功能,頁面元素平凡改動的時候是否需要大批量的修改腳本,及測驗不同資料時是否也要修改腳本,那么能想到這些我們的初始目標差不多就有了
- 生成測驗用例執行結果報告
2.生成測驗用例執行日志
3.用例執行失敗或者執行完成后自動發送郵件報告
- 用例執行失敗或者成功時截取圖片
5.資料驅動(讀取測驗資料,減少腳本維護成本)
專案代碼
config.ini # 存放專案跟路徑
[project]
project_path = D:\Petrochina_Retail_Test_Project

elementData.xlsx # 存放所有的測驗資料及元素
一個excel檔案,不方便貼里面內容(先過,別管里面是啥了 哈哈 后面再找吧)
mail_receiver.txt# 存放郵件接收者的賬號 , 可以添加多個賬號以‘,’號分割
**@qq.com
公共方法models下面的檔案:
doconfini.py
'''
2 Code description:read conf file
3 Create time:
4 Developer:
5 '''
6
7 import logging
8 import configparser
9 from retail.config.conf import *
10 from retail.test_case.models.log import Logger
11
12 log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
13 class DoConfIni(object):
14
15 def __init__(self):
16 """
17
18 :param filename:
19 """
20 self.cf = configparser.ConfigParser()
21
22 # 從ini檔案中讀資料
23 def getConfValue(self,filename,section,name):
24 """
25
26 :param config:
27 :param name:
28 :return:
29 """
30 try:
31 self.cf.read(filename)
32 value = self.cf.get(section,name)
33 except Exception as e:
34 log.logger.exception('read file [%s] for [%s] failed , did not get the value' %(filename,section))
35 raise e
36 else:
37 log.logger.info('read excel value [%s] successed! ' %value)
38 return value
39 # 向ini檔案中寫資料
40 def writeConfValue(self,filename, section, name, value):
41 """
42
43 :param section: section
44 :param name: value name
45 :param value: value
46 :return: none
47 """
48 try:
49 self.cf.add_section(section)
50 self.cf.set(section, name, value)
51 self.cf.write(open(filename, 'w'))
52 except Exception :
53 log.logger.exception('section %s has been exist!' %section)
54 raise configparser.DuplicateSectionError(section)
55 else:
56 log.logger.info('write section'+section+'with value '+value+' successed!')
57
58 if __name__ == '__main__':
59 file_path = currPath
60 print(file_path)
61 read_config = DoConfIni()
62
63 value = read_config.getConfValue(os.path.join(currPath,'config.ini'),'project','project_path')
64 print(value)
65
66 read_config.writeConfValue(os.path.join(currPath,'config.ini'),'tesesection', 'name', 'hello word')
doexcel.py
1 '''
2 Code description:read excel.xlsx, get values
3 Create time:
4 Developer:
5 '''
6
7 import xlrd
8 import os
9 import logging
10 from retail.config import conf
11 from retail.test_case.models.log import Logger
12
13 log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
14
15 class ReadExcel(object):
16
17 def __init__(self,fileName='elementDate.xlsx',sheetName='elementsInfo'):
18 """
19
20 :param fileName:
21 :param sheetName:
22 """
23 try:
24 self.dataFile = os.path.join(conf.dataPath, fileName)
25 self.workBook = xlrd.open_workbook(self.dataFile)
26 self.sheetName = self.workBook.sheet_by_name(sheetName)
27 except Exception:
28 log.logger.exception('init class ReadExcel fail', exc_info=True)
29 raise
30 else:
31 log.logger.info('initing class ReadExcel')
32 # 讀excel中的資料
33 def readExcel(self,rownum,colnum):
34 """
35
36 :param rownum:
37 :param colnum:
38 :return:
39 """
40 try:
41 value = self.sheetName.cell(rownum,colnum).value
42 except Exception:
43 log.logger.exception('read value from excel file fail', exc_info=True)
44 raise
45 else:
46 log.logger.info('reading value [%s] from excel file [%s] completed' %(value, self.dataFile))
47 return value
48
49 if __name__ == '__main__':
50 cellValue = ReadExcel().readExcel(1,3)
51 print((cellValue))
log.py
1 '''
2 Code description:log info
3 Create time:
4 Developer:
5 '''
6
7 import logging
8 import time
9
10
11 class Logger(object):
12 def __init__(self, logger, CmdLevel=logging.INFO, FileLevel=logging.INFO):
13 """
14
15 :param logger:
16 :param CmdLevel:
17 :param FileLevel:
18 """
19 self.logger = logging.getLogger(logger)
20 self.logger.setLevel(logging.DEBUG) # 設定日志輸出的默認級別
21 # 日志輸出格式
22 fmt = logging.Formatter('%(asctime)s - %(filename)s:[%(lineno)s] - [%(levelname)s] - %(message)s')
23 # 日志檔案名稱
24 # self.LogFileName = os.path.join(conf.log_path, "{0}.log".format(time.strftime("%Y-%m-%d")))# %H_%M_%S
25 currTime = time.strftime("%Y-%m-%d")
26 self.LogFileName = r'D:\Petrochina_Retail_Test_Project\retail\report\Log\log'+currTime+'.log'
27 # 設定控制臺輸出
28 # sh = logging.StreamHandler()
29 # sh.setFormatter(fmt)
30 # sh.setLevel(CmdLevel)# 日志級別
31
32 # 設定檔案輸出
33 fh = logging.FileHandler(self.LogFileName)
34 fh.setFormatter(fmt)
35 fh.setLevel(FileLevel)# 日志級別
36
37 # self.logger.addHandler(sh)
38 self.logger.addHandler(fh)
39
40 # def debug(self, message):
41 # """
42 #
43 # :param message:
44 # :return:
45 # """
46 # self.logger.debug(message)
47 #
48 # def info(self,message):
49 # """
50 #
51 # :param message:
52 # :return:
53 # """
54 # self.logger.info(message)
55 #
56 # def warn(self,message):
57 # """
58 #
59 # :param message:
60 # :return:
61 # """
62 # self.logger.warning(message)
63 #
64 # def error(self,message):
65 # """
66 #
67 # :param message:
68 # :return:
69 # """
70 # self.logger.error(message)
71 #
72 # def criti(self,message):
73 # """
74 #
75 # :param message:
76 # :return:
77 # """
78 # self.logger.critical(message)
79
80 if __name__ == '__main__':
81 logger = Logger("fox",CmdLevel=logging.DEBUG, FileLevel=logging.DEBUG)
82 logger.logger.debug("debug")
83 logger.logger.log(logging.ERROR,'%(module)s %(info)s',{'module':'log日志','info':'error'}) #ERROR,log日志 error
sendmail.py
1 '''
2 Code description:send email
3 Create time:
4 Developer:
5 '''
6
7 import smtplib
8 from email.mime.text import MIMEText
9 from email.header import Header
10 import os
11 from retail.config import conf
12 from retail.test_case.models.log import Logger
13
14 log = Logger(__name__)
15 # 郵件發送介面
16 class SendMail(object):
17 '''
18 郵件配置資訊
19 '''
20 def __init__(self,
21 receiver,
22 subject='Retail 系統測驗報告',
23 server='smtp.qq.com',
24 fromuser='281754043@qq.com',
25 frompassword='gifhhsbgqyovbhhc',
26 sender='281754043@qq.com'):
27 """
28
29 :param receiver:
30 :param subject:
31 :param server:
32 :param fromuser:
33 :param frompassword:
34 :param sender:
35 """
36
37 self._server = server
38 self._fromuser = fromuser
39 self._frompassword = frompassword
40 self._sender = sender
41 self._receiver = receiver
42 self._subject = subject
43
44 def sendEmail(self, fileName):
45 """
46
47 :param filename:
48 :return:
49 """
50 # 打開報告檔案讀取檔案內容
51 try:
52 f = open(os.path.join(conf.reportPath, fileName), 'rb')
53 fileMsg = f.read()
54 except Exception:
55 log.logger.exception('open or read file [%s] failed,No such file or directory: %s' %(fileName, conf.reportPath))
56 log.logger.info('open and read file [%s] successed!' %fileName)
57 else:
58 f.close()
59 # 郵件主題
60 subject = 'Python test report' #
61 # 郵件設定
62 msg = MIMEText(fileMsg, 'html', 'utf-8')
63 msg['subject'] = Header(subject, 'utf-8')
64 msg['from'] = self._sender
65 # 連接服務器,登錄服務器,發送郵件
66 try:
67 smtp = smtplib.SMTP()
68 smtp.connect(self._server)
69 smtp.login(self._fromuser, self._frompassword)
70 except Exception:
71 log.logger.exception('connect [%s] server failed or username and password incorrect!' %smtp)
72 else:
73 log.logger.info('email server [%s] login success!' %smtp)
74 try:
75 smtp.sendmail(self._sender, self._receiver, msg.as_string())
76 except Exception:
77 log.logger.exception('send email failed!')
78 else:
79 log.logger.info('send email successed!')
80
81
82 # 從檔案中讀取郵件接收人資訊
83 def getReceiverInfo(fileName):
84 '''
85 :param filename: 讀取接收郵件人資訊
86 :return: 接收郵件人資訊
87 '''
88 try:
89 openFile = open(os.path.join(conf.dataPath, fileName))
90 except Exception:
91 log.logger.exception('open or read file [%s] failed,No such file or directory: %s' %(fileName, conf.dataPath))
92 else:
93 log.logger.info('open file [%s] successed!' %fileName)
94 for line in openFile:
95 msg = [i.strip() for i in line.split(',')]
96 log.logger.info('reading [%s] and got receiver value is [%s]' %(fileName, msg))
97 return msg
98
99 if __name__ == '__main__':
100 readMsg=getReceiverInfo('mail_receiver.txt')
101 sendmail = SendMail(readMsg)
102 sendmail.sendEmail('2018-09-21 17_44_04.html')
strhandle.py
1 '''
2 Code description: string handle
3 Create time:
4 Developer:
5 '''
6
7 import logging
8 from retail.test_case.models.log import Logger
9
10 log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
11 def strhandle(str):
12 """
13
14 :param str:
15 :return:
16 """
17 #初始化字符、數字、空格、特殊字符的計數
18 try:
19 lowerCase = 0
20 upperCase = 0
21 number = 0
22 other = 0
23 for stritem in str:
24 #如果在字串中有小寫字母,那么小寫字母的數量+1
25 if stritem.islower():
26 lowerCase += 1
27 #如果在字串中有數字,那么數字的數量+1
28 elif stritem.isdigit():
29 number += 1
30 elif stritem.isupper():# 大寫字母
31 upperCase +=1
32 #如果在字串中有空格,那么空格的數量+1
33 else:
34 other += 1
35 return lowerCase, upperCase, number, other
36 except Exception as e:
37 log.logger.exception('string handle error , please check!', exc_info=True)
38 raise e
39
40
41 if __name__=='__main__':
42 list = ['qwert','erwer']
43 lowercase, uppercase, number, other = strhandle(list[0])
44 print ("該字串中的小寫字母有:%d" %lowercase)
45 print ("該字串中的大寫寫字母有:%d" %uppercase)
46 print ("該字串中的數字有:%d" %number)
47 print ("該字串中的特殊字符有:%d" %other)
testreport.py
1 '''
2 Code description:test report
3 Create time:
4 Developer:
5 '''
6
7
8 import time
9 import logging
10 import unittest
11 from BeautifulReport import BeautifulReport
12 import HTMLTestRunner
13 from retail.config import conf
14 from retail.test_case.models.log import Logger
15
16 log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
17 # 用HTMLTestRunner 實作的測驗報告
18 def testreport():
19 """
20
21 :return:
22 """
23 currTime = time.strftime('%Y-%m-%d %H_%M_%S')
24 fileName = conf.reportPath + r'\report' + currTime + '.html'
25 try:
26 fp = open(fileName, 'wb')
27 except Exception :
28 log.logger.exception('[%s] open error cause Failed to generate test report' %fileName)
29 else:
30 runner = HTMLTestRunner.HTMLTestRunner\
31 (stream=fp, title='Retail sys測驗報告',
32 description='處理器:Intel(R) Core(TM) '
33 'i5-6200U CPU @ 2030GHz 2.40 GHz '
34 '記憶體:8G 系統型別: 64位 版本: windows 10 家庭中文版')
35 log.logger.info('successed to generate test report [%s]' %fileName)
36 return runner, fp, fileName
37 #
38 def addTc(TCpath = conf.tcPath, rule = '*TC.py'):
39 """
40
41 :param TCpath: 測驗用例存放路徑
42 :param rule: 匹配的測驗用例檔案
43 :return: 測驗套件
44 """
45 discover = unittest.defaultTestLoader.discover(TCpath, rule)
46
47 return discover
48 # 用BeautifulReport模塊實作測驗報告
49 def runTc(discover):
50 """
51
52 :param discover: 測驗套件
53 :return:
54 """
55 currTime = time.strftime('%Y-%m-%d %H_%M_%S')
56 fileName = currTime+'.html'
57 try:
58 result = BeautifulReport(discover)
59 result.report(filename=fileName, description='測驗報告', log_path=conf.reportPath)
60 except Exception:
61 log.logger.exception('Failed to generate test report', exc_info=True)
62 else:
63 log.logger.info('successed to generate test report [%s]' % fileName)
64 return fileName
65
66 if __name__ == '__main__':
67 testreport()
68 suite = addTc(rule = '*TC.py')
69 runTc(suite)
driver.py
1 '''
2 Code description:save all driver info
3 Create time:
4 Developer:
5 '''
6
7 from selenium import webdriver
8 import logging
9 import sys
10 from retail.test_case.models.log import Logger
11
12
13 log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
14 class WDriver(object):
15
16 # Firefox driver
17 def fireFoxDriver(self):
18 """
19
20 :return:
21 """
22 try:
23 self.driver = webdriver.Firefox()
24 except Exception as e:
25 log.logger.exception('FireFoxDriverServer.exe executable needs to be in PATH. Please download!', exc_info=True)
26 raise e
27 else:
28 log.logger.info('%s:found the Firefox driver [%s] successed !' %(sys._getframe().f_code.co_name,self.driver))
29 return self.driver
30
31 # chrom driver
32 def chromeDriver(self):
33 """
34
35 :return:
36 """
37 try:
38 # option = webdriver.ChromeOptions()# 實作不打開瀏覽器 執行web自動化測驗腳本
39 # option.add_argument('headless')#
40 # self.driver = webdriver.Chrome(chrome_options=option)
41 self.driver = webdriver.Chrome()
42 except Exception as e:
43 log.logger.exception('ChromeDriverServer.exe executable needs to be in PATH. Please download!',
44 exc_info=True)
45 raise e
46 else:
47 log.logger.info('%s:found the chrome driver [%s] successed !' % (sys._getframe().f_code.co_name, self.driver))
48 return self.driver
49
50
51 # Ie driver
52 def ieDriver(self):
53 """
54
55 :return:
56 """
57 try:
58 self.driver = webdriver.Ie()
59 except Exception as e:
60 log.logger.exception('IEDriverServer.exe executable needs to be in PATH. Please download!',
61 exc_info=True)
62 raise e
63 else:
64 log.logger.info('%s:found the IE driver [%s] successed !' % (sys._getframe().f_code.co_name, self.driver))
65 return self.driver
66
67
68 if __name__ == '__main__':
69 WDrive=WDriver()
70 WDrive.fireFoxDriver()
myunittest.py
1 '''
2 Code description:unittest framwork
3 Create time:
4 Developer:
5 '''
6
7 from retail.test_case.models.driver import WDriver
8 import logging
9 import unittest
10 from retail.test_case.page_obj.login_page import LoginPage
11 from retail.test_case.models.log import Logger
12 from selenium import webdriver
13
14 log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
15 class MyunitTest(unittest.TestCase):
16 """
17
18 """
19
20 # add by xuechao at 2018.09.19
21 @classmethod
22 def setUpClass(cls): # 一個測驗類(檔案)執行一次打開瀏覽器, 節約每個用例打開一次瀏覽器的時間
23
24 #cls.driver = WDriver().fireFoxDriver()
25 cls.driver = WDriver().chromeDriver()
26 cls.driver.maximize_window()
27 log.logger.info('opened the browser successed!')
28 # ----------------------------
29
30 def setUp(self):
31 """
32
33 :return:
34 """
35 self.login = LoginPage(self.driver)
36 self.login.open()
37 log.logger.info('************************starting run test cases************************')
38
39 def tearDown(self):
40 """
41
42 :return:
43 """
44 self.driver.refresh()
45 log.logger.info('************************test case run completed************************')
46
47 # add by linuxchao at 2018.09.19
48 @classmethod
49 def tearDownClass(cls):
50 cls.driver.quit()
51 log.logger.info('quit the browser success!')
52 #----------------------------
53 if __name__ == '__main__':
54 unittest.main()
目前為止,我需要的所有的公共方法都撰寫完了, 后期再需要別的方法可以加,下面我們就開始撰寫我們的測驗用例,由于我們使用的是PageObject模式,那么我們需要設計一個basepage頁面,所有的頁面或者說模塊全部繼承這個basepage,basepage主要撰寫所有頁面的公共方法
base_page.py
登錄頁面
login_page.py
登錄測驗用例
LoginTc.py
修改密碼頁面
modifypw_page.py
修改密碼測驗用例
ModifyPw.py
會員檔案查詢頁面
memberquery_page.py
會員檔案查詢用例
MemberQueryTc.py
執行測驗用例
RunTc.py
from BeautifulReport import BeautifulReport 這個報告需要自己網上找一下(很多類似的測驗報告原始碼,不一定非使用本案例中的報告模板)
報告展示
有付出才有匯報,接下來看下們的成果
1.截圖:
創建規則失敗時截圖

登錄成功截圖

用例執行日志:
日志
測驗報告:

總結
看到結果還是挺有成就感的,郵件的截圖我沒發,因為我是內網不知道什么原因郵件服務器連接不上,但是使用外網單獨測驗郵件發送是沒什么問題的!
就寫這么多吧,其他頁面的用例設計思路都是一樣的,因為所有的用例彼此都是獨立的,所以多與少都不影響!
軟體測驗是IT相關行業中最容易入門的學科~不需要開發人員燒腦的邏輯思維、不需要運維人員24小時的隨時待命,需要的是細心認真的態度和IT相關知識點廣度的了解,每個測驗人員從入行到成為專業大牛的成長路線可劃分為:軟體測驗、自動化測驗、測驗開發工程師 3個階段,
如果你不想再體驗一次自學時找不到資料,沒人解答問題,堅持幾天便放棄的感受的話,可以加我們的軟體測驗交流群 313782132 ,里面有各種軟體測驗資料和技術交流,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/197064.html
標籤:python
下一篇:Windows環境下Python 3.6.8 import matplotlib.pyplot 時出現的 importError: DLLload failed:找不到指定的模塊
