在 Linux 平台上進行大型項目開發過程中,測試人員需要定期(通常是每天),從代碼庫中更新代碼、編譯版本、運行全部測試腳本、收集並發布測試結果。這個過程既繁瑣又耗時。通常我們希望能在下班後能自動完成這一系列操作,本文將講述如何利用 Python 腳本輕松實現這一過程。
測試人員從代碼庫(例如 CVS )遷出代碼的過程中,需要手動輸入訪問密碼,而 Python 提供了 Pexpect 模塊則能夠將手動輸入密碼這一過程自動化。當然 Pexpect 也可以用來和 ssh、ftp、passwd、telnet 等命令行進行自動化交互。這裡我們以 CVS 為例展示如何利用 Pexpect 從代碼庫遷出代碼。
try: chkout_cmd = 'cvs co project_code' #從代碼庫遷出 project_code 的內容 child = pexpect.spawn(chkout_cmd) child.expect('password:') child.sendline('your-password') #請替換"your-password"為真實密碼 child.interact() except: pass #忽略遷出代碼中的錯誤
在清單 1 中,我們用命令"cvs co project_code"從代碼庫中遷出了 project_code 的內容,我們也可以用該命令來更新已經遷出的代碼。只需要將命令"cvs update" 傳給類 pexpect.spawn()即可,詳細的實現請參考代碼文件。這裡 interact()函數是必須的,用來在交互的方式下控制該子進程。有時代碼庫中會存在目錄不一致行情況,遷出代碼會因報錯終止,所以需要異常處理(try ... execpt)來忽略該錯誤。
《Python核心編程 第二版》.(Wesley J. Chun ).[高清PDF中文版] http://www.linuxidc.com/Linux/2013-06/85425.htm
《Python開發技術詳解》.( 周偉,宗傑).[高清PDF掃描版+隨書視頻+代碼] http://www.linuxidc.com/Linux/2013-11/92693.htm
Python腳本獲取Linux系統信息 http://www.linuxidc.com/Linux/2013-08/88531.htm
在Ubuntu下用Python搭建桌面算法交易研究環境 http://www.linuxidc.com/Linux/2013-11/92534.htm
測試人員獲取最新的代碼之後,就要對源碼進行編譯,並且運行測試用例。Python 語言提供了多種方法如 os.system()/os.popen()來執行一條命令,這裡我們推薦用 subprocess 模塊來創建子進程,完成代碼編譯和運行測試用例。因為 subprocess 支持主進程和子進程的交互,同時也支持主進程和子進程是同步執行還是異步執行。由於本文中的各個功能模塊有都先後依賴關系,所以全部采用的是主進程和子進程同步模式執行。
編譯代碼
build_cmd = 'build_command_for_your_code' #請在這裡配置編譯命令 build_proc = subprocess.Popen(build_cmd, stdin=None, stdout=None, stderr=None, shell=True) build_proc.wait() #等待子進程結束 assert (0 == build_proc.returncode)
在一些系統中我們編譯代碼采用的是腳本文件(如 shell 腳本),那麼我們仍然可以如下命令來完成代碼編譯工作。
subprocess.call(["code_compile.sh"])
運行測試腳本
在編譯完成代碼之後,我們同樣可以調用 subprocess.Popen 來創建子進程運行測試用例。如果測試人員的測試用例已經寫成了測試例腳本,我們則可以用 subprocess.call()來執行測試例腳本文件,代碼實現就不再贅述。有些系統會直接把詳細日志輸出到屏幕上,那麼我們可以用重定向命令"2>&1"把屏幕輸出寫文件。
ut_cmd = 'Your_unit_test_command 2>&1 > %s' %self.debug_log #debug_log 定義在__init__函數中,用來存儲詳細日志
我們的項目采用敏捷開發,為了更好的反應敏捷開發周期,我們希望存儲日志的目錄名不但能夠指明的具體日期,同時也能反映敏捷(迭代)開發階段,這樣相關人員在查看相應目錄中的日志時,能夠清楚的明白日志實在在哪個迭代周期的哪一天產生的。本文使用文件 summary 作為運行測試用例後生成的匯總日志,用文件 log.txt 用來存儲詳細日志。如下圖所示,在共享目錄 SharedFiles 中存儲了一些列迭代周期中的日志。
SharedFiles ├── Sprint10-20130823121500 │ ├── log.txt │ └── summary ├── Sprint10-20130826152715 │ ├── log.txt │ └── summary ├── Sprint10-20130828165235
為了能夠讓目錄名反映敏捷開發周期,我們需要自己定義一個配置文件(txt 或 xml 均可)。由於 Python 已經很好的支持了 XML 解析,並且 XML 文件作為配置也是當前的流行趨勢。本文就以 XML 解析為例進行說明。本文使用的 XML 文件名是 Sprint.xml,清單 6 是該 xml 的概要內容
<sprint-schedule> <min-sprint>10</min-sprint> <max-sprint>20</max-sprint> <sprint10>20130814</sprint10> <sprint11>20130828</sprint11> … … <sprint19>20131218</sprint19> <sprint20>20140101</sprint20> </sprint-schedule>
關於 xml 解析 Python 提供了多種方法。本文采用 minidom 對 xml 文件進行解析,清單 7 是相關處理代碼。
cur_date = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time())) # 首先獲取當前系統日期 xmldoc = minidom.parse(xml_file) min_num_node = xmldoc.getElementsByTagName('min-sprint')[0] min_num = int(min_num_node.firstChild.data) #解析出迭代開發周期的起始周期 max_num_node = xmldoc.getElementsByTagName('max-sprint')[0] max_num = int(max_num_node.firstChild.data) #解析出迭代開發周期的終止周期 cur_num = min_num #遍歷所有迭代周期,取出當前迭代周期的開始時間和當前的系統時間對比,從而確定當前位於哪一個迭代周期。 while cur_num <= max_num : node_name = 'sprint' + str(cur_num) cur_node = xmldoc.getElementsByTagName(node_name)[0] sprint_date = cur_node.firstChild.data if sprint_date < cur_date[0:7]: cur_num = cur_num + 1 else: break
這樣 cur_num 就指向了當前的迭代開發周期。然後,我們就可以根據當前日期和開發階段創建對應的日志目錄名了,最後把運行結果存儲到該目錄下,參見清單 8 實現。
log_dir = self.share_dir + '/Sprint' + str(cur_num) + '-' + cur_date #share_dir 為共享目錄,定義在初始化函數中 os.mkdir(log_dir) os.system('mv %s %s' %(self.debug_fullname, log_dir)) #debug_fullname,詳細日志文件名(含目錄),定義在初始化函數中 os.system('mv %s %s' %(self.sum_fullname, log_dir)) #sum_fullname,匯總日志的全路徑文件名,定義在初始化函數中
關於測試結果的發布,本文並沒有把測試結果以自動化的形式發送郵件,而是手動在每個開發周期結束時,群發郵件給相關人員。或者在驗證失敗後,通知相關的開發人員,這是由於作者所在團隊項目代碼提交頻率不是很高。在更大型的項目中,往往需要增加自動發送郵件的功能,相關實現本文不再贅述。
更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-08/105599p2.htm