本人在網上查找了不少作自動化的教程和實例,偶然的一個機會接觸到了selenium,以爲很是好用。後來就在網上查閱各類selenium的教程,可是網上的東西真的是太多了,以致於不少東西參考完後沒法系統的學習和應用,有一次在網上隨意搜索,找到了-蟲師-寫的《Selenium2自動化測試實戰基於Python語言》,以爲真心不錯,內容也很調理,爲了方便本身學習和知識的整理,就把其中蟲師編寫的自動化項目教程整理一下,有興趣的能夠去參看蟲師的博客http://www.cnblogs.com/fnng/javascript
如下整理的只是書中自動化項目的知識內容,介紹怎麼搭建自動化測試框架、執行自動化測試用例、生成自動化測試報告、發送測試報告郵件....,具體的Selenium和python語言基礎不作介紹html
1、項目結構介紹java
下面逐級介紹此目錄與文件的做用node
mztstpro/python
|-----bbs/web
| |-----data/chrome
| |-----report/瀏覽器
| |------image/服務器
| |-----test_case/架構
| |------models/
| |----driver.py
| |----function.py
| |----myunit.py
| |------page_obj/
| |----*Page.py
| |------*_sta.py
|-----driver/
|-----package/
|-----run_bbs_test.py
|-----startip.bat
|-----自動化測試項目說明文檔.docx
1.mztestpro測試項目
bbs:用於存放BBS項目的測試用例、測試報告和測試數據等。
driver:用於存放瀏覽器驅動。如selenium-server-standalone-2.47.0jar、chromedriver.exe、IEDriverServer.exe等。在執行測試前根據執行場景將瀏覽器驅動複製到系統環境path目錄下。
package:用於存放自動化所用到的擴展包。例如:HTMLTestRunner.py屬於一個單獨模塊
run_bbs_test.py:項目主程序。用來運行社區(BBS)自動化用例。
startup.bat:用於啓動selenium server,默認啓動driver目錄下的selenium-server-standalone-2.44.0.jar。
自動化測試項目說明文檔.docx:介紹當前項目的架構、配置和使用說明。
2.bbs目錄
data:該目錄用來存放測試相關數據。
report:用於存放HTML測試報告。其下面建立了image目錄用於存放測試過程當中的截圖。
test_case:測試用例目錄,用於存放測試用例及相關模塊。
3.test_case
models:該目錄下存放了一些公共的配置函數及公共類。
page_obj:該目錄用於存放測試用例的頁面對象(Page Object)。根據自定義規則,以「*Page.py」命名的文件爲封裝的頁面對象文件。
*_sta.py:測試用例文件。根據測試文件匹配規則,以「*_sta.py」命名的文件被看成自動化測試用例執行。
2、編寫公共模塊
首先定義驅動文件:
...\mztestpro\bbs\test_case\models\driver.py
driver.py
# __author__ = 'Ztiny' # -*-coding:utf-8-*- from selenium.webdriver import Remote from selenium import webdriver # 啓動瀏覽器驅動 def browser(): driver = webdriver.Firefox() # host = '192.168.0.132:5555' #運行主機 :端口號(默認本機:127.0.0.1:4444) # dc = {'browserName':'internet explorer','version':'','platfrom':'WINDOWS','javascriptEnabled':True} # # dc = {'browserName':'firefox','version':'','platfrom':'ANY','javascriptEnabled':True,'marionette':False,}#指定瀏覽器 ('chrome','firefox') # driver = Remote(command_executor='http://' + host + '/wd/hub', # desired_capabilities=dc) return driver if __name__ == '__main__': dr = browser() dr.get("http://www.mayi.com") dr.quit()
定義瀏覽器驅動函數browser(),該函數能夠進行配置,根據咱們的須要,配置測試用例在不一樣的主機及瀏覽器下運行。
自定義測試框架類:
...\mztestpro\bbs\test_case\models\myunit.py
myunit.py
# __author__ = 'Ztiny' #-*-coding:utf-8-*- from selenium import webdriver from driver import browser import unittest class MyTest(unittest.TestCase): def setUp(self): self.driver = browser() self.driver.implicitly_wait(10) self.driver.maximize_window() def tearDown(self): self.driver.quit() if __name__ == '__main__': unittest.main()
定義MyTest()類用於集成unittest.TestCase類,由於筆者建立的全部測試類中setUp()與tearDown()方法所作的事情相同,因此,將他們抽象爲MyTest()類,好處就是在編寫測試用例時再也不考慮這兩個方法的實現。
定義截圖函數:
...\mztestpro\bbs\test_case\models\function.py
function.py
# __author__ = 'Ztiny' #-*-coding:utf-8-*- from selenium import webdriver import os #截圖函數 def insert_img(driver, file_name): base_dir = os.path.dirname(os.path.dirname(__file__)) base_dir = str(base_dir) base_dir = base_dir.replace('\\','/') base = base_dir.split('test_case')[0] file_path = base + "report/image/" + file_name driver.get_screenshot_as_file(file_path) if __name__ == '__main__': driver = webdriver.Ie() driver.get("http://www.baidu.com") insert_img(driver,'baidu.jpg') driver.quit()
建立截圖函數insert_img(),爲了保持自動化項目的移植性,採用相對路徑的方式將測試截圖保持到.\report\image目錄中。
3、編寫Page Object
首先建立基礎Page基礎類(百度主頁爲例):
...\mztestpro\bbs\test_case\page_obj\base.py
base.py
# __author__ = 'Ztiny' #-*-coding:utf-8-*- class Page(object): ''' 頁面基礎類,用於全部頁面的繼承 ''' baidu_url = 'https://www.baidu.com' def __init__(self,selenium_driver,base_url = baidu_url,parent =None): self.base_url = base_url self.driver = selenium_driver self.timeout = 30 self.parent = parent def _open(self,url): url = self.base_url + url self.driver.get(url) assert self.on_page(),'Did not land on %s' % url def find_element(self,*loc): return self.driver.find_element(*loc) def find_elements(self,*loc): return self.driver.find_elements(*loc) def open(self): self._open(self.url) def on_page(self): return (self.driver.current_url).encode('utf-8') == (self.base_url + self.url)
def script(self,src): return self.driver.execute_script(src)
建立頁面基礎類,經過__init__()方法初始化參數:瀏覽器驅動、URL地址、超時時長等。定義基本方法:open()用於打開BBS地址:find_element()和find_elements()分別用來定位單個與多個元素;建立script()方法能夠更簡便地調用JavaScript代碼。固然還能夠對更多的WebDriver方法進行重定義。
建立BBS登陸對象類:
...\mztestpro\bbs\test_case\page_obj\loginPage.py
loginPage.py
# __author__ = 'Ztiny' # -*-coding:utf-8-*- from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.by import By from base import Page from time import sleep class login(Page): ''' 用戶登陸界面 ''' url = '/' #Action baidu_login_user_loc = (By.LINK_TEXT,u'登陸') #彈出登陸窗口 def baidu_login(self): self.find_element(*self.baidu_login_user_loc).click() login_username_loc = (By.ID,'TANGRAM__PSP_8__userName') login_password_loc = (By.ID,'TANGRAM__PSP_8__password') login_button_loc = (By.ID,'TANGRAM__PSP_8__submit') #登陸用戶名 def login_username(self, username): self.find_element(*self.login_username_loc).clear() self.find_element(*self.login_username_loc).send_keys(username) #登陸密碼 def login_password(self, password): self.find_element(*self.login_password_loc).clear() self.find_element(*self.login_password_loc).send_keys(password) #登陸按鈕 def login_button(self): self.find_element(*self.login_button_loc).click() #統一登陸入口 def user_login(self, username="**********@qq.com", password="*********"): '''獲取用戶名和麪登陸''' self.open() self.baidu_login() self.login_username(username) self.login_password(password) self.login_button() sleep(2)
user_error_hint_loc = (By.LINK_TEXT,u"帳號不能爲空") pawd_error_hint_loc = (By.LINK_TEXT,u"密碼不能爲空") user_login_success_loc = (By.LINK_TEXT,u'Ztiny') #用戶名錯誤提示 def user_error_hint(self): return self.find_element(*self.user_error_hint_loc).text #密碼錯誤提示 def pawd_error_hint(self): return self.find_element(*self.pawd_error_hint_loc).text #登陸成功用戶名 def user_login_success(self):
return self.find_element(*self.user_login_success_loc).text
建立登陸頁面對象,對用戶登陸頁面上的用戶名/密碼輸入框、登陸按鈕和提示信息等元素的定位進行封裝。除此以外,還建立user_login()方法做爲系通通一登陸的入口。關於對操做步驟的封裝能夠放在Page Object當中,也能夠放在測試用例當中,這個主要根據具體的需求來衡量。這裏之因此要放在Page Object當中,主要考慮到還會有其餘的測試用例調用到該登陸方法。爲username 和 password 入參數設置了默認值是爲了方便其餘用例在調用user_login()時不用再傳遞登陸用戶信息,由於該系統大多用例的執行使用該帳號便可,同時也方便了在帳號失效時的修改。
4、編寫測試用例
如今開始編寫測試用程序,由於前面已經作好了基礎工做,此時測試用例的編寫將會簡單的許多,更能集中精力考慮用例的設計和事項。
建立BBS登陸類:
...\mztestpro\bbs\test_case\login_sta.py
此處須要注意文件名的建立。例如,假設登陸頁的對象命名爲loginPage.py,那麼關於測試登陸的用例文件應該命名爲login_sta.py,這樣方便後期用例報錯時問題跟蹤。儘可能把一個頁面上的元素定位封裝到一個「*Page.py」文件中,把針對這個頁面的測試用例集中到一個「*_sta.py」文件中
login_sta.py
# __author__ = 'Ztiny' #-*-coding:utf-8-*- from time import sleep import unittest, random ,sys sys.path.append("./models") sys.path.append("./page_obj") from models import myunit, function from page_obj.loginPage import login class loginTest(myunit.MyTest): '''測試用戶登陸''' def user_login_verify(self, username='',password=''): login(self.driver).user_login(username,password)
def test_login1(self): '''用戶名、密碼爲空登陸''' self.user_login_verify() po = login(self.driver) self.assertEqual(po.user_error_hint(),"帳號不能爲空") self.assertEqual(po.pawd_error_hint()."密碼不能爲空") function.insert_img(self.driver,"user_pawd_empty.jpg") def test_login2(self): '''用戶名正確,密碼爲空登陸''' self.user_login_verify(username="*******") po = login(self.driver) self.assertEqual(po.pawd_error_hint(),"密碼不能爲空") function.insert_img(self.driver,"paqd_empty.jpg") def test_login3(self): '''用戶名爲空,密碼正確''' self.user_login_verify(password="*******") po = login(self.driver) self.assertEqual(po.user_error_hint(),"帳號不能爲空") function.insert_img(self.driver,"user_empty.jpg") def test_login4(self): '''用戶名與密碼不匹配''' character = random.choice('abcdefghijklmnopqrstuvwxyz') username = "zhangsan" + character self.user_login_verify(username=username,password="123456") po = login(self.driver) self.assertEqual(po.pawd_error_hint(),"密碼與帳號不匹配") function.insert_img(self.driver,"user_pwad_error.jpg") def test_login5(self): '''用戶名、密碼正確''' self.user_login_verify(username='********@qq.com',password='********') sleep(2) po = login(self.driver) self.assertEqual(po.user_login_success(), u'Ztiny') function.insert_img(self.driver ,"user_pwd_ture.jpg") if __name__ == '__main__': unittest.main()
首先建立loginTest()類,繼承myunit.Mytest()類,關於Mytest()類的實現,請翻看前面代碼。這樣就省去了在每個測試類中實現一遍setUp()和tearDown()方法。
建立user_login_verify()方法,並調用loginPage.py中定義的user_login()方法。爲何不直接調用呢?由於user_login()的入參已經設置了默認值,緣由前面已經解釋,這裏須要從新將其入參的默認值設置爲空便可。
前三條測試用例很好理解,分別驗證:
第四條用例驗證錯誤用戶名和密碼登陸。在當前系統中若是反覆使用固定錯誤的用戶名和密碼,系統會彈出驗證碼輸入框。爲了不這種狀況的發生,就須要用戶名進行隨機變化,此處的作法用固定前綴「zhangsan」,末尾字符從a~z中隨機一個字符與前綴進行拼接。
第五條用例驗證正確的用戶名和密碼登陸,經過獲取用戶名做爲斷言信息
在上面的測試用例中,每條測試用例結束時都調用function.py文件中的insert_img函數進行截圖。當用例運行完成後,打開...\report\image\目錄將會看到用例執行的截圖文件,如圖:
5、執行測試用例
爲了在測試用例運行過程當中不影響作其餘事,筆者選擇調用遠程主機或虛擬機來運行測試用例,那麼這裏就須要使用Selenium Grid(其包含Selenium Server)來調用遠程節點。
建立...\mztestpro\startup.bat文件,用於啓動...\mztestpro\driver\目錄下的Selenium Server。
startup.bat
@echo off echo 啓動hub java -jar .\mztestpro\driver\selenium-server-standalone-2.40.0.jar -role hub -host 192.168.0.102 -port 4444 echo 啓動node java -jar .\mztestpro\driver\selenium-server-standalone-2.40.0.jar -role node -port 5555 -hub http://192.168.0.102:4444/grid/register
雙擊startup.bat文件,啓動Selenium Server建立主hub節點。在遠程主機或虛擬機中通樣須要啓動Selenium Server建立node節點。
建立用例執行程序:...\mztestpro\run_bbs_test.py
run_bbs_test.py
# __author__ = 'Ztiny' #-*-coding:utf-8-*- from HTMLTestRunner import HTMLTestRunner from email.mime.text import MIMEText import smtplib import unittest import time import os # =========================郵件接收者============================ mailto_list=["********@qq.com"] #============= 設置服務器,用戶名、口令以及郵箱的後綴=============== mail_host="smtp.163.com" mail_user="******@163.com" mail_pass="*******" #===========================發送郵件============================ def send_mail(to_list,file_new): ''''' to_list:發給誰 sub:主題 content:內容 send_mail("aaa@126.com","sub","content") ''' f = open(file_new, 'rb') mail_body = f.read() f.close() me=mail_user msg = MIMEText(mail_body,'html','utf-8') msg['Subject'] = u'自動化測試報告' msg['From'] = me msg['To'] = ";".join(to_list) try: s = smtplib.SMTP() s.connect(mail_host,25) s.login(mail_user,mail_pass) s.sendmail(me, to_list, msg.as_string()) s.close() return True except Exception, e: print str(e) return False #==============查找測試報告目錄,找到最新生成的測試報告文件========== def new_report(testreport): lists = os.listdir(testreport) lists.sort(key=lambda fn:os.path.getatime(testreport + "\\" + fn)) file_new = os.path.join(testreport,lists[-1]) print(file_new) return file_new if __name__ == '__main__': now = time.strftime("%Y-%m-%d %H_%M_%S") filename = './bbs/report/' + now +'result.html' fp = open(filename,'wb') runner = HTMLTestRunner(stream=fp, title=u'百度登陸自動化測試報告', description=u'環境 :window 7 瀏覽器:firefox') discover = unittest.defaultTestLoader.discover('./bbs/test_case', pattern='*_sta.py') runner.run(discover) fp.close() file_path = new_report('./bbs/report/') if send_mail(mailto_list,file_path): print u"發送成功" else: print u"發送失敗"
執行過程當中並無任何改動,集成HTMLTestRunner生成的HTML測試報告,以及集成自動發郵件功能等。惟一須要注意的是,腳本中的路徑建議使用相對路徑,以便於項目被移動到任意目錄下執行。
打開...\mztestpro\driver.py 文件,修改腳本運行的節點及瀏覽器。如今能夠經過運行run_bbs_test.py來執行測試項目了。
小結:
若是你完成了前面的操做,那麼這只是自動化項目的開始,不過,咱們已經把基本架構設計完成,後面大部分工做就是編寫各個頁面的*Page.py以及測試用*_sta.py。在這個過程當中會遇到各類各樣的問題,如元素定位、架構的擴展,須要讀者本身去克服這些問題。
PS:對自動化感興趣的同窗能夠加QQ羣:539725853,歡迎加入交流!