如何記錄selenium自動化測試過程當中接口的調用信息

上一篇博客,我寫了python自動化框架的一些知識和粗淺的見解,在上一篇中我也給本身提出一個需求:若是記錄在測試過程當中接口的調用狀況?提出這個需求,我以爲是有意義的。你在測試過程當中確定會遇到一些莫名其妙的問題,好比:web某個頁面一直在刷進度條,致使你定位元素失敗,可是,你再手動操做一遍可能沒法復現....對於咱們來講,確定會遇到許多相似的問題。你會發現有時候僅僅靠一張截圖,你遠遠找不到bug的緣由。這時候,我在想若是我能拿到這一系列操做所調用的接口信息多好,我就能明白爲何發生這種問題了。好比一直在刷進度條我以爲有幾種狀況:1.後端一直在等待某個接口的響應信息。2.網絡緣由致使,接口響應很慢(局域網通常不多出現這類問題)、3.前端工程師沒有動態的把這個進度條display="None"....不論何種緣由,我拿到相關的接口信息,就能對錯誤逐個排除。好比我發現某個接口的響應時間很長.....或者全部接口的響應的時間可能是大於1s的,又或者都正常響應,原來js沒有動態改變進度的屬性?反正不管如何我拿到自動化操做的接口信息是沒有壞處的吧?(小小的缺點我後面提到)css

那麼問題是,咱們如何精準的拿到這些信息?我開始的想法是經過firebug去拿,firebug咱們平時用的也比較多,能夠方便的看到控制檯信息(js的執行狀況)和網絡信息(接口調用狀況),可是我查了不少資料都沒有辦法完整的把這些信息給導出來....可是,我很快的想到了Fiddler。Fiddler是目前爲止我用的最好最順手的一款http抓包工具(不要和我提什麼wireshark,雖然通過網卡的信息它都能抓可是僅對http協議來講,真不如fiddler牛逼,誰用誰知道),更重要的是因爲它是個代理服務器,因此能抓任何設置其爲代理的終端,包括手機...想到這,心中一陣竊喜。下面我先說說思路,而後再詳細的說明,我是怎麼作的。個人思路以下:html

1.設置fiddler過濾一下抓取信息,如:只抓取host爲:*.csdn.net的接口信息。前端

2.測試執行開始前,打開fiddler。
python

3.當執行一個test時,先在fiddler控制檯輸入cls,清空當前sessions,防止接口信息過多或混在一塊兒不方便排查錯誤。web

4.當執行test完畢,若是有錯誤,則保存此test執行過程當中的全部sessions至一個文件夾。無錯誤不作操做(若是你非要保存也是能夠的)正則表達式

5.重複2-3的步驟,直至全部測試結束。windows

6.測試執行結束後,關閉fiddler。後端

上面的想法,其實也是很簡單的,咱們再一個個看看如何實現:
瀏覽器

對於步驟1/2/5  用python調用控制檯打開fiddler是有問題的(主進程會阻塞,其餘應用程序沒問題),改用AutoIt的run方法,關閉沒問題。安全

對於3/4是要想一想辦法的。對於自動化人員來講AutoIt您應該是接觸過了,若是沒有就去看看吧!AutoIt有弊端有優勢,最大的優勢就是編寫簡單、腳本能轉換成exe.最大的缺點:windows非標準控件沒法獲取。萬幸的是Fiddler的控制檯輸入框能被AutoIt識別!還有就是如何改寫Fiddler的Scripts。(咱們的需求很簡單,別被嚇到了)

因此第一步:咱們編寫清除fiddler session的腳本,轉換成C_interface.exe。腳本簡單到不能簡單了,以下:

 

Example()
Func Example()
    Local $hWnd = WinWait("[Title:Telerik Fiddler Web Debugger]", "", 10)
	WinActivate($hWnd);激活當前窗口
    ControlFocus($hWnd, "","[CLASS:WindowsForms10.EDIT.app.0.141b42a_r6_ad1;NAME:txtExec]")
    ControlSetText($hWnd, "", "[CLASS:WindowsForms10.EDIT.app.0.141b42a_r6_ad1;NAME:txtExec]","cls")
	Send("{ENTER}")
 EndFunc   ;

 

 

 照顧一下,剛開始看AutoIt的同窗,Title中的Telerik Fiddler Web Debugger與ControlFocus中的CLASS、NAME是經過AutoIt Window info這個工具捕捉的,咱們的可能不同貼圖一張:

咱們寫完了了清除session後,再來寫下保存接口信息的腳本,也很簡單保存爲D_interface.exe:

Example()
Func Example()
    Local $parment=$CmdLine[1];接受控制檯數據,$parment爲fiddler接口保存路徑
    Local $hWnd = WinWait("[Title:Telerik Fiddler Web Debugger]", "", 10)
    WinActivate($hWnd);激活當前窗口
    ControlFocus($hWnd, "","[CLASS:WindowsForms10.EDIT.app.0.141b42a_r6_ad1;NAME:txtExec]")
    ControlSetText($hWnd, "", "[CLASS:WindowsForms10.EDIT.app.0.141b42a_r6_ad1;NAME:txtExec]","dump "&$parment)
    Send("{ENTER}")
    IF WinActive("[Title:Cannot Save SAZ]") Then
      ControlClick("[Title:Cannot Save SAZ]","","Button1")
    EndIf
EndFunc   ;

標紅部分的解釋是:當Fiddler沒有session時(雖然不太可能出現這種狀況),執行dump命令會彈出個對話框,這時候要關閉對話框!!若是不關閉的話下面對fiddler的操做會出現問題,由於這時候彈出框是fiddler的頂級窗口,可能致使腳本中使用Enter鍵無效...

其次,因爲python調用控制檯啓動Fiddler有問題(具體問題緣由未知),因此咱們也用AutoIt編寫,並轉換成S_interface.exe:

Example()
Func Example()
    Local $parment=$CmdLine[1]
	Run($parment)
EndFunc   ;

最後,咱們改下Fiddler的Script的,從菜單的Rules->Customer Rules打開腳本剪輯器,直接拉到script的末端修改方法OnExecAction以下:

   ......
        case "dump":
            UI.actSelectAll();
            var bpMethod = sParams[1]
            //UI.actSaveSessionsToZip(CONFIG.GetPath("Captures") + "dump.saz");
            UI.actSaveSessionsToZip(bpMethod)

            FiddlerObject.StatusText = "Dumped all sessions to " +bpMethod;
            //FiddlerObject.alert(bpMethod);
            UI.actRemoveAllSessions();
            return true;

修改case 'dump'的狀況,bpMethod是由命令bump空格後的參數。對應於上文咱們AutoIt腳本中的$parment參數(由控制檯輸入)。

上面咱們的準備工做的作的差很少了,總結一下,幹了下面的幾個事情:

1.用AutoIt生成了清除Fiddler session的一個exe

2.用AutoIt生成了保存Fiddler session的一個exe

3.修改了Fiddler的Script接受一個保存session路徑的一個參數

在完成了以上工做後,咱們來進行測試!注意:在此以前咱們要明白一些事情:

1.用Fiddler作代理後,可能影響接口的加載速度,畢竟有個第三者。可是我以爲速度影響在web自動化上不是那麼重要的事情,畢竟現實中的訪問速度確定比你公司內部訪問速度更差。(缺點之一)

2.用Fiddler作代理後,咱們知道在訪問https的時候好比訪問百度,可能顯示非安全連接,咱們日常的作法是把fiddler的證書導入瀏覽器(具體百度上有說明),可是咱們webdriver啓動的是個空白的瀏覽器,如何能自動加載Fiddler證書

3.用Fiddler作代理後,若是Fiddler崩潰或者沒啓動起來形成沒法聯網致使全部腳本沒法運行,這個風險咱們如何規避?

第一個問題跳過,咱們看看第二個問題

在路徑C:\Python27\Lib\site-packages\selenium\webdriver\firefox\firefox_profile.py下定義了一個FirefoxProfile類,這個類咱們平時可能不太用的上,可是用不上不表明他不重要,這個類是個管理瀏覽器插件的類。咱們說明一下:

1.其構造函數傳火狐瀏覽器的插件路徑。火狐瀏覽器的插件通常在C:\Users\***\AppData\Roaming\Mozilla\Firefox\Profiles\****.default-*****"這個路徑下面。構造函數會把這個路徑下的東西copy到c:\\users\\pf-211x3\\appdata\\local\\temp\\***\\webdriver-py-profilecopy這個文件夾下。

2.encoded函數。這個函數的文檔屬性這樣解釋:"A zipped, base64 encoded string of profile directory for use with remote WebDriver JSON wire protocol"具體很麼意思呢?就是這個函數會把上文中咱們提到的c:\\users\\pf-211x3\\appdata\\local\\temp\\***\\webdriver-py-profilecopy這個文件夾壓縮成ZIP格式文件,而後對這個文件進行base64的編碼,當啓動瀏覽器的時候,會將這個編碼一同發給服務器,服務器再對他base64解碼、解壓縮將您本地火狐插件完完整整的複製到新啓動的空白瀏覽器上,那麼咱們新啓動的瀏覽器就擁有了本地瀏覽器全部的插件了。

3.set_preference。傳遞一個鍵值對,就是設置火狐瀏覽器的選項,好比設置代理等等....

4.add_extension。傳遞一個***.xpi的路徑,就是設置瀏覽器加載的插件,好比啓動瀏覽器加載firebug,把firebug插件路徑傳遞給add_extension便可

通過我對FirefoxProfile類的說明,您大概知道了問題二的解決辦法了吧,對的就是向FirefoxProfile類中傳遞插件的路徑。可是C:\Users\***\AppData\Roaming\Mozilla\Firefox\Profiles\****.default-*****"這個文件是比較大的反正個人是50M,將這樣一個大的文件通過步驟2的操做,是個費事費力的事情。因此大家會發現,若是把完整的插件路徑傳遞給FirefoxProfile,通過一系列的壓縮、傳遞,啓動本地瀏覽器會很是很是慢!通過排除和嘗試法,我發現火狐對證書的控制是由插件文件夾下的cert8.db控制的,全部咱們把這個文件給拷貝出來放在一個文件夾中,單獨傳這個文件夾路徑便可。

第三個問題:

瀏覽器的代理有幾下幾種:1.不使用代理。2.自動檢測此網絡的代理設置。3.使用系統代理。4.手動配置代理。5,自動代理配置

對於1和4你們都明白;對於5也還好就是:寫一個腳本告訴瀏覽器什麼樣的域名我要代理,其餘的不使用代理(具體百度);對於2和3我多少有點不知道他怎麼用,對於3使用系統代理個人實踐就是若是我啓動了fiddler它就使用了fiddler代理,若是沒有啓動就不使用代理,看起來挺智能了。我也不太清楚這樣爲何...因此對於問題三我也是糾結的:第1、若是設置手動代理看起來是沒問題的,就怕fiddler故障了,而後雪崩...第2、我着實不太瞭解我使用系統代理對不對?這個你們本身看好了。我反正就用系統代理了,至少能知足個人想法:萬一fiddler故障了也沒啥,大不了就抓不到接口數據唄,其餘的還能正常的跑....

最後,就是在咱們上篇繼承unnitest的run方法裏面,修改一點點代碼,也很簡單(紅色標識了):

 

......
def
run(self, result=None): orig_result = result if result is None: result = self.defaultTestResult() startTestRun = getattr(result, 'startTestRun', None) if startTestRun is not None: startTestRun() self._resultForDoCleanups = result screenshot_path=getattr(result,"screenshot_path",False)
dir_name = os.path.dirname(__file__) # 當前腳本根目錄

#由於fiddler保存儘可能要使用絕對路徑,若是使用相對路徑會保存到安裝目錄下,這是咱們不但願的
sessiong_path = dir_name + "/" + "Error_session"#默認session保存路徑
if not screenshot_path: screenshot_path=self.__screenshot_path else: if os.path.dirname(screenshot_path):#若是是絕對路徑 sessiong_path=os.path.dirname(screenshot_path)+"/Error_session"#拿到運行test的根目錄+FiddlerSessions result.startTest(self) testMethod = getattr(self, self._testMethodName) if (getattr(self.__class__, "__unittest_skip__", False) or getattr(testMethod, "__unittest_skip__", False)): # If the class or method was skipped. try: skip_why = (getattr(self.__class__, '__unittest_skip_why__', '') or getattr(testMethod, '__unittest_skip_why__', '')) self._addSkip(result, skip_why) finally: result.stopTest(self) return try: success = False try: self.setUp() except SkipTest as e: self._addSkip(result, str(e)) except KeyboardInterrupt: raise except: result.addError(self, sys.exc_info())#啓動setUp失敗直接判斷出錯 else: try: testMethod() except KeyboardInterrupt: raise except (self.failureException,exceptions.WebDriverException):#若是是斷言錯誤或WebDriverException,類型爲fail,且增長截圖 #增長截圖 browser=self.getbrowser()#嘗試拿瀏覽器實例 if browser: filename=self.__class__.__name__+"_"+self._testMethodName+".png"#格式:類名+方面名稱 browser.get_screenshot_as_file(screenshot_path+"\\"+filename) reback_filename=filename else: reback_filename=None #保存sessions數據 sessionfile_name=self.__class__.__name__+"_"+self._testMethodName+"_err.saz"#注意格式是saz os.popen(dir_name+"/"+"Tools/D_interface.exe "+sessiong_path+"\\"+sessionfile_name)#控制檯運行D_interface.exe由AutoIt生成,保存出錯的session result.addFailure(self, sys.exc_info(),reback_filename)#回傳截圖名稱給report,以便能顯示在報告中 except SkipTest as e:#若是爲跳過的異常,類型爲Skip異常
......

 

最後個人demo文檔結構大概是這樣的:

 

 

其中Error_session是保存錯誤的session;FireFox_profile是咱們說到的火狐證書插件;Tools是咱們轉換的3個簡單的exe程序;screen_shot存放錯誤截圖;IqunxingTest.py是咱們改寫的unnitest類,咱們新建測試demo腳本:

#coding=utf-8
import IqunxingTest
import HTMLTestRunner
import sys,os
import unittest
from  selenium import webdriver
from  selenium.webdriver.firefox import firefox_profile
import time
dir_name = os.path.dirname(__file__)  # 拿到根目錄
class Mydemo(IqunxingTest.IqunxingTest):
    u'''測試CSDN登陸'''
    @classmethod
    def setUpClass(cls):
        profile=firefox_profile.FirefoxProfile(profile_directory=dir_name+"/FireFox_profile")
        profile.set_preference("network.proxy.type", 5)#將瀏覽器代理設置爲系統代理
        cls.browser=webdriver.Firefox(firefox_profile=profile)#啓動帶插件的瀏覽器
        cls.browser.implicitly_wait(10)
    @unittest.Myskip
    def test1(self):
        u'''打開csdn'''
        browser=self.browser
        browser.get("http://www.csdn.net/")
    @unittest.Myskip
    def test2(self):
        u'''csdn登陸'''
        os.popen(dir_name+"/"+"Tools/C_interface.exe")#在test開始前,清空Fiddler session信息
        browser = self.browser
        browser.find_element_by_link_text(u"登陸").click()
        time.sleep(1)
        browser.find_element_by_id("username").send_keys("test")
        time.sleep(1)
        browser.find_element_by_id("password").send_keys("test")
        time.sleep(1)
        browser.find_element_by_class_name("logging").click()#點擊登陸
        if not browser.find_element_by_class_name("phr_first").is_displayed():#若是沒有登陸成功是找不到這個控件會報錯
            self.assertTrue(False,"login failed")
if __name__ == '__main__':
    fiddler_path = "C:\Program Files (x86)\Fiddler2\Fiddler.exe"#您的Fiddler路徑
    s = os.popen(dir_name + "/Tools/S_interface.exe " + "\"" + fiddler_path + "\"")#啓動Fidder
    module_name=os.path.basename(sys.argv[0]).split(".")[0]
    module=__import__(module_name)
    runner=HTMLTestRunner.HTMLTestRunner("reprot.html")
    all_suite=unittest.defaultTestLoader.loadTestsFromModule(module)
    runner.run(all_suite)
    os.popen('''taskkill /f /im "Fiddler.exe"''')#測試完成後關閉fiddler

由於咱們要找一些有用的sesssion信息,可喜的是Fiddler能過濾一些你設置完的信息,個人過濾信息以下:

由於測試CSDN,因此我只展現域名爲*.csdn.net的會話;另外,一些css,js,png等無用信息我也隱藏了(正則表達式隱藏)。好了萬事具有,咱們運行下這個demo:最後在Error_session下保存了咱們test2操做的全部http信息文件名爲:Mydemo_test2_err.saz(過濾的除外),同時在screen_shot下保存錯誤的截圖。咱們直接用fiddler打開這個saz文件:

 

從上面的截圖能夠看出來,咱們保存的session是完整的(過濾的除外)。並且咱們看到了咱們點擊登陸時,使用的接口以及傳遞的相關信息。固然,咱們點擊Fiddler其餘標籤事能獲取一切咱們想獲取的信息。

這一節個人思路說完了...固然,你可能用不上這些,可是你至少了解到了AutoIt以及selenium的一些知識!仍是那句:若是認爲我說的有些道理,個人辛苦是值得的(畢竟寫了一天);若是認爲沒用,請一笑而過~~

下個話題:selenium相關應用!!

相關文章
相關標籤/搜索