馬天鳴,梁 琛
(1.上海工程技術大學 電子電氣工程學院,上海 201620; 2.電信科學技術第一研究所有限公司,上海 200032)
在項目的開發過程中,新版本的連續發布使回歸測試的需求更為頻繁,在項目周期長,模塊功能復雜的情況下,采用手工方式對系統功能進行多次重復的驗證時,會消耗大量時間,增加測試成本。因此,選擇正確的回歸測試策略來改進測試的效率和有效性是很有必要的。使用自動化測試[1-3]的方式來進行回歸測試,可以進行大規模、長時間和多周期的測試,既減少測試人員的工作量,又保證了測試的效率和準確性。
為了實現全國各局之間、局與各電信運營商網絡之間的通信暢通,實時監測全網通斷情況,及時、準確定位故障線路,對全網設備、資源優化提供科學依據等運營目標,迫切需要建設一套覆蓋全網的電話自動撥測系統。
根據電話自動撥測系統需求變動不頻繁、項目周期長以及系統界面穩定、變動少的特點,引入UI自動化測試來達到擴大測試覆蓋率,降低回歸測試成本的效果。
Selenium[4-8]是一個主要用于web應用程序自動化測試[9]的工具集合,最初是為網站自動化測試而開發的[10],它支持各種主流瀏覽器和多種編程語言,可以跨平臺使用。該工具能模擬用戶操作,在瀏覽器中直接運行,擁有足夠好的用戶體驗[11],其開源優勢以及功能特點符合電話自動撥測系統對于自動化測試工具的要求。
電話自動撥測系統是B/S(瀏覽器/服務器)架構的系統,由統計分析、端局狀態、端局管理、號碼管理、撥測管理和系統管理六個模塊組成,如圖1所示。
其中,登錄是進入系統的前提,端局管理和號碼管理兩個模塊需要對大量的省市端局和號碼進行增加、刪除、修改、關聯等操作,系統管理則需要添加各端局的登錄用戶、配置對應的權限,步驟重復繁瑣,僅以手工的方式對這部分功能進行測試會消耗大量的時間和精力,增加測試人員的負擔。故需要引入適合web應用程序的自動化工具對系統進行回歸測試,從而提高測試效率。
Selenium是一種基于瀏覽器的自動化測試工具,提供了一種跨平臺、跨瀏覽器的端到端web自動化解決方案。Selenium支持主流的瀏覽器,包括Firefox、IE、Chrome、Safari和Opera等,它可以模擬使用者與瀏覽器之間的交互,如訪問網站、點擊鏈接、填寫表單、瀏覽網頁等。Selenium前后共經歷了三個版本,分別是Selenium1.0、Selenium2.0和Selenium3.0,現使用最新版本3.0來做測試,Selenium3.0主要包括三個部分:Selenium IDE、Selenium WebDriver 和Selenium Grid。
Selenium IDE作為瀏覽器Mozilla Firefox的插件,不需要任何編程邏輯來編寫測試腳本,它通過與瀏覽器的交互可以進行錄制和回放,并能把錄制的操作以多種編程語言的形式導出測試用例。
Selenium WebDriver提供了web自動化所需的API(應用程序接口),主要用作瀏覽器控制、頁面元素選擇和調試。使用Selenium WebDriver前要選擇一種語言來編寫自動化腳本且需要由selenium client library支持。
Selenium Grid提供了在不同瀏覽器上運行Selenium的能力,它的作用是分布式執行測試,可以控制多臺機器以及多個瀏覽器執行測試用例。在測試用例較多的情況下,通過Selenium Grid可以提高測試效率。
python是一門被廣泛應用的高級編程語言,它語法簡單、簡潔易懂、框架復用性高、可移植性強,并且提供了大量的內置庫、函數以及用戶編寫的第三方庫,眾多開源的科學計算軟件包都提供了python的調用接口[12],從而可以容易地實現一些復雜的功能。python支持Selenium client library,既可以使用C/C++進行擴展,又能嵌入其他編程語言中,故選擇python來編寫自動化測試腳本。
Selenium的測試過程分為六個步驟,分別是制定測試計劃、編寫測試腳本、優化測試腳本、執行測試腳本、生成測試報告和郵件發送報告,如圖2所示。

圖2 Selenium自動化測試過程
1.4.1 制定測試計劃
自動化項目的測試計劃做得越詳細,后期就越能按部就班地去執行,測試的成功率也就越高。對于系統而言,并非所有的功能點都適合使用自動化來進行回歸測試,因此需要羅列所有符合Selenium測試條件的模塊并對其功能點進行細化來設計測試用例,然后再實施后面五個步驟。
1.4.2 編寫測試腳本
單元測試框架是編寫自動化測試用例的基礎[4]。unittest一般稱為PyUnit,是從Java程序中廣泛應用的JUnit啟發而來的,可以使用unittest為任何項目創建全面的測試套件,unittest也是python中用來測試各種標準類庫模塊的[13]。現使用unittest單元測試框架來創建基于python的Selenium Webdriver測試腳本。unittest適用于web自動化測試用例的開發和執行,它可以用來組織和執行系統各模塊的測試用例。
1.4.3 優化測試腳本
編寫的腳本只包含元素定位和頁面操作,沒有校驗測試用例中預期結果和程序返回的實際結果是否一致,因此需要對腳本進行優化,通過斷言的方式來判定測試用例執行成功與否,如等價校驗、邏輯校驗和異常校驗等。
1.4.4 執行測試腳本
測試腳本是以py為后綴的文件,在代碼編輯器中運行當前文件,腳本便自動開始執行,Chrome瀏覽器立即彈出并按測試用例中的步驟依次執行,在結束時瀏覽器的窗口會自動進行關閉。
1.4.5 生成測試報告
使用unittest的拓展HTMLTestRunner生成格式友好的HTML測試報告,既能獲取測試結果的概況,又能深入查看報告的細節。
1.4.6 郵件發送報告
以郵件附件的形式自動發送測試報告至相關技術人員的郵箱,這樣能讓他們及時了解系統缺陷的詳細情況,有助于其后續工作的安排和開展。
電話自動撥測系統中的系統管理、端局管理和號碼管理分別牽涉到大量的端局用戶、省市端局和撥測號碼,用手動測試的方法進行重復的操作會消耗不少時間,而且降低了測試人員對于工作的積極性,使用Selenium工具對這三個模塊中部分適合自動化測試的功能點進行回歸測試,比如對撥測號碼以及端局用戶信息的新增,刪除和修改等,這樣可以減輕重復操作的負擔,從而提高測試人員的工作積極性。
系統登錄雖然不在系統管理、端局管理和號碼管理三個模塊的范圍內,但由于操作任何一個模塊都無法逾越這個步驟,因此該部分也納入了自動化測試的范圍。
2.2.1 系統登陸驗證碼
登錄電話自動撥測系統的前提是輸入正確的用戶名、密碼和由四個隨機數字組成的驗證碼,用戶名和密碼是固定的,驗證碼則是隨機生成的,需要正確識別才能進行后續操作,系統登錄框如圖3所示。

圖3 登錄框的顯示
主要有四個方法來解決通過驗證碼的問題:(1)去掉驗證碼部分的代碼;(2)使用一個萬能驗證碼;(3)通過cookie直接登錄系統,從而避開驗證碼這一步驟;(4)識別驗證碼中的數字并登錄系統。第一種方法去掉驗證環節會給系統帶來安全風險,第二種方法則需要通過開發的協助才能完成,第三種方法不能對驗證碼進行自動化測試,因此只有最后一種才是安全,可行的方法。
要識別驗證碼首先要對數字區域進行截取,webdriver能對瀏覽器頁面進行截圖,但是整個瀏覽器頁面過大,需要具體定位到驗證碼圖片的所在位置。通過驗證碼的標簽id定位到該標簽所在頁面的像素位置,再獲取標簽大小,確定圖片的寬和高,從而獲得驗證碼的位置和大小。在截取驗證碼圖片后,使之轉化成灰度圖并增強它的飽和度,此時保存后的圖片如圖4所示。

圖4 處理后的驗證碼圖片
從圖4可以看出,此時驗證碼的辨識度比較高,通過把圖片中的內容轉化為字符串的操作,成功地辨識出驗證碼中的數字,使得系統登錄的整個過程得以自動完成。
2.2.2 單元測試框架
單元測試是一項對技術要求很高的工作,只有白盒測試人員和軟件開發人員才能勝任,但用單元測試框架做單元測試卻十分簡單,而且單元測試框架不僅可以用來做單元測試,還適用于不同類型的自動化測試[14]。
單元測試框架是構建自動化測試用例的基礎,在python中有多種單元測試框架,如unittest、doctest、pytest和nose等,電話自動撥測系統使用的是unittest,它可以為任何項目創建全面的測試套件,主要由Test Case、Test Suite、Test Runner和Test Fixture四個核心組件構成。在執行Test Suite(測試套件)后,unittest在命令行會輸出對應的測試結果,使用unittest的拓展HTMLTestRunner可以進一步生成Test Report(測試報告),如圖5所示。

圖5 unittest單元測試框架
(1)Test Case[15-18](測試用例)。一個測試用例是在unittest中執行測試的最小單元,它通過assert方法來驗證一組特定的操作和輸入以后得到的具體響應。unittest提供了TestCase基類,可以用來創建測試用例。
(2)Test Suite(測試套件)。一個測試套件是多個測試或測試用例的集合,是針對被測程序的對應的功能和模塊創建的一組測試,一個測試套件內的測試用例將一起執行。
(3)Test Runner(測試執行器)。測試執行器負責測試執行調度并且生成測試結果給用戶。測試執行器可以使用圖形界面、文本界面或者特定的返回值來展示測試執行結果。
(4)Test Fixture(測試夾具)。通過使用測試夾具,可以定義在單個或多個測試執行之前的準備工作和測試執行之后的清理工作。
(5)Test Report(測試報告)。測試報告用來展示所有執行用例的成功或者失敗狀態的匯總,執行失敗的測試步驟的預期結果與實際結果,還有整體運行狀況和運行時間的匯總。
2.2.3 頁面定位元素
頁面元素都是由HTML代碼組成的,它們之間有層級地組織起來,每個元素有不同的標簽名和屬性值,WebDriver就是根據這些信息來定位元素的。Selenium主要有id、name、tag、class、link_text、partial link、XPath、CSS_selector八種元素定位的方法,這些方法根據一定的標準取查找元素,如果元素被正常定位,那么WebElement實例返回,否則拋出NoSuchElementException的異常。
電話自動撥測系統主要使用id、name和class屬性來查找元素,這三種方式是最為普遍和快捷的,當上述方法無法生效時,使用XPath的方式可以靈活地運用絕對或相對路徑來進行定位。
基于元素id的定位方法是通過查找Web頁面上的元素id值來獲取元素,比較簡單,適合Web元素id固定的情況來使用,對于動態分配Web元素id的情況不能使用[11]。由于頁面中元素的id是唯一的,因此通過id定位元素是最佳方法。
基于元素name的定位方法是另一種常見的查找元素的方式,可以通過匹配name的值來定位一個或者一組元素,如果匹配成功則返回查找的元素,匹配失敗則拋出異常。
基于元素class的定位方法用來關聯css中定義的屬性,class可以指定元素的類名,其用法和id、name相類似。
基于元素XPath的定位方法是通過元素的路徑來完成對元素的查找,XPath是XML路徑語言,可以用來定位XML文檔中元素的位置。Xpath分兩種定位方法,一種是用絕對/相對路徑來定位,另一種是使用元素屬性來進行定位。
2.2.4 操作頁面元素
Webdriver提供很多用來與瀏覽器交互的功能和設置,可以通過使用Webdriver的功能和方法來實現與瀏覽器窗口、警告、框架和彈出窗口的交互。自動化過程中與頁面元素進行交互的方法都是由WebElement接口提供的,頁面元素包含文本框、文本域、按鈕、單選框、多選框和下拉列表等。
WebElement提供了一些功能和方法來實現與網頁元素的交互,WebElement的功能如size(獲取元素大小)、tage_name(獲取元素的標簽名稱)和text(獲取元素的文本值)等,方法如clear(清除文本)、send_keys(*value)模擬按鍵輸入和click()(單擊元素)等。WebElement與各種HTML控件的自動化交互,例如在輸入框內寫入文本、單擊一個按鈕和選擇單復選框等。
2.2.5 頁面元素等待
當沒有定位到標簽元素時,除了找錯標簽這個原因以外,還有一種可能就是標簽由于網速等因素沒有及時加載出來,直接獲取會導致程序運行時報錯,因此需要設置線程等待,Selenium提供了兩種等待機制:隱式等待和顯式等待。
隱式等待對于解決網絡延遲或者利用Ajax動態加載元素所導致的程序響應時間不一致,是非常有效的,WebDriver類提供了implicitly_wait()方法來設置超時時間;顯式等待可以只作用于僅有同步需求的測試用例,WebDriver提供了WebDriverWait類和expected_conditions類來實現顯式等待[13]。
在處理同步問題上,顯式等待的可操控性更佳,處理方式更靈活,故在電話自動撥測系統腳本的編寫中使用顯式等待的機制。
2.2.6 控制瀏覽器
瀏覽器的工具欄中一般都有前進、后退以及刷新的按鈕,這些功能比較實用,在網頁操作中經常會用到,Selenium Webdriver提供了這些操作瀏覽器的方法。
瀏覽器全屏模式可以用maxmize_window()的方法來實現,該方法無需設置參數;當想要讓瀏覽器以某種特定的大小運行時,可以用set_window_size()的方法來設置瀏覽器的窗口大小。
Webdriver提供了forward(),back()和refresh()來模擬瀏覽器前進、后退以及刷新/重新加載的按鍵功能。
測試腳本中驗證實際和預期結果是否一致是很重要的,unittest的TestCase類提供了很多實用的方法來校驗預期結果與程序返回的實際結果是否一致,如assertEqual/assertNotEqual、assertTrue/assertFalse、assertIn/assertNotIn等,這些方法要求必須滿足某些條件才能繼續執行接下來的測試。如果給定的斷言通過了,下面的測試代碼則被執行,否則將會導致測試立即停止并且給出異常信息。
執行測試套件后,unittest在命令行輸出測試結果,但是給相關技術人員發送命令行日志并不是一個明智的選擇,生成一個包含所有用例執行情況的測試報告是很有必要的。unittest沒有相應的內置模塊能創建格式友好的測試報告,可以通過使用unittest的拓展HTMLTestRunner來實現,腳本生成的測試報告如圖6所示。

圖6 HTML測試報告
測試報告為HTML文件,可以用瀏覽器進行讀取,它包含測試開始時間、持續時長、狀態統計以及每個測試用例執行結果的詳細描述。圖6為系統管理、端局管理和號碼管理三個模塊選取部分用例所生成的測試報告,其中執行失敗的用例可以通過展開Detail來對問題進行具體的定位和分析。

圖7 郵件自動發送測試報告
以郵件的形式自動發送測試報告是電話自動撥測系統的重要需求之一,當測試腳本執行完成以后,便會自動向項目相關人員的郵箱發送測試報告。yagmail是python的一個第三方庫,通過使用yagmail能以比較簡單的方法來實現自動發送郵件的功能。在發送郵件時,除了填寫主題和正文外,還可以增加抄送人和添加附件等。
由于HTMLTestRunner報告在展示時引用了Bootstrap樣式庫,當作為正文寫在郵件中時,會導致樣式丟失,所以作為附件發送更為合適,如圖7所示。
為減少手工測試工作量,提高測試效率,使用Selenium自動化測試工具對撥測系統中三個主要模塊進行回歸測試。測試結果表明,該方法可以模擬手工操作反復地執行并生成直觀、易于定位bug的HTML測試報告,最后以郵件附件形式每天定時發送給相關技術人員。相比手工測試,此方法節省了重復執行測試用例的時間,提高了測試效率,為開發能盡早修復缺陷,相關人員能及時了解測試情況提供了便利。