最近項目上使用了RF快速實現了一些驗收測試的自動化case,感覺不錯,很好用,下面就記錄一下使用RF實現自動化的過程。
什么是RF?
RF是一種測試框架,幫助測試人員在其框架下快速實現驗收測試的自動化。提供很多的擴展庫供你使用,在沒有任何一種語言編程基礎的情況下也能實現一些自動化測試用例。
說白了,任何一種框架的作用就是幫你完成一些基礎的工作,使你更加關注於要測試的業務邏輯,而不是關心技術細節,這些技術細節包括用例如何運行、如何組織、日志怎么記錄,怎么展現,如何與CI集成等等。
使用RF框架與Jenkins CI工具結合,可以很容易的實現測試的遠程部署、運行與結果展現。比起重寫造輪子,自己寫一套系統,這種方式還是快得多,最適合剛剛起步的項目。
RF能做什么?
RF能做什么取決於使用什么樣的擴展框架,RF提供的默認內置庫與外部擴展庫,當然也可以自己寫擴展庫來定制功能。基本提供的庫已經可以滿足一般的測試需求了,包括對手機端、網頁端的自動化測試,還有API接口的測試。
編寫RF文件
RF文件通常以robot為后綴名,並且提供了很多的編輯工具,方便的進行robot文件的編輯。我使用的是pycharm的RF插件進行編輯,因為需要使用python寫大量的擴展庫,所以在pycharm里面統一進行robot與py文件的編輯,還是很方便的。或者使用官方的RIDE也是很好的選擇,純圖形化界面,方便團隊沒有開發經驗的人參與其中。
RF文件的結構
先看一個RF文件示例:
如上所示,一個RF文件通常包括三個節點:
-
Settings節點:
1. 設置此test suite的setup與tearndown操作
2. 此test suite 中每個test case的setup與tearndown操作
3. 指定測試模板test template
4. 指定此test suite引用的資源文件的位置
5. 使用Library關鍵字引用RF標准庫,或者自定義庫: -
Test Cases節點:
1. 可以定義一個普通的測試用例
2. 也可以調用模板,並給模板傳入它所需要的參數
3. 測試用例里面所調用的關鍵詞可能來自下面三個地方:
* 當前test suite文件的keywords節點中定義的keyword
* Setttings節點指定的資源文件中所定義的keyword
* 內建的BuiltIn庫中定義的keyword -
Keywords節點:
1. keyword可以理解為一個公用的方法,供test case使用
2. keyword可以傳入參數,返回結果
3. RF也提供很多邏輯判斷IF,循環FOR等關鍵詞
Resource資源文件的結構
其實resource文件與普通robot文件沒多大區別,只不過它是被導入的庫文件,通常用來定義一些公用的變量和keywords:
編寫自己的Library文件
RF運行使用很多語言編寫自己的Library文件,這里選擇python編寫,首先看一下對已存在的庫文件的擴展
對selenium2library庫文件的擴展:
1 # 導入Selenium2Library模塊 2 from Selenium2Library import Selenium2Library模塊 3 from selenium.common.exceptions import StaleElementReferenceException 4 import time 5 6 7 def _get_table_field_value(element, field): 8 return element.find_element_by_xpath("./td[@field='" + field + "']").text.strip() 9 10 # 繼承Selenium2Library 11 class CustomSeleniumLibrary(Selenium2Library): 12 def get_table_row_count(self, table_locator): 13 attempts = 0 14 while True: 15 try: 16 table = self._table_element_finder.find(self._current_browser(), table_locator) 17 return len(table.find_elements_by_xpath("./tbody/tr")) 18 except StaleElementReferenceException: 19 time.sleep(1) 20 if attempts >= 1: 21 raise AssertionError("Cell in table %s could not be found." % table_locator) 22 else: 23 pass 24 attempts += 1 25 26 def get_user_search_results(self, table_locator, row_index): 27 table = self._table_element_finder.find(self._current_browser(), table_locator) 28 ret = [] 29 if table is not None: 30 rows = table.find_elements_by_xpath("./tbody/tr") 31 if len(rows) <= 0: 32 return None 33 row_index = int(row_index) 34 if len(rows)-1 < row_index: 35 raise AssertionError("The row index '%s' is large than row length '%s'." % (row_index, len(rows))) 36 for row in rows: 37 dic = { 38 'userId': _get_table_field_value(row, 'userId'), 39 'nickName': _get_table_field_value(row, 'nickName'), 40 'realName': _get_table_field_value(row, 'realName'), 41 'mobile': _get_table_field_value(row, 'mobile'), 42 'idNo': _get_table_field_value(row, 'idNo'), 43 'userType': _get_table_field_value(row, 'userType'), 44 'verifyUserStatus': _get_table_field_value(row, 'verifyUserStatus'), 45 'operator': _get_table_field_value(row, 'operater'), 46 'operateTime': _get_table_field_value(row, 'operateTime'), 47 } 48 ret.append(dic) 49 return ret[row_index] 50 else: 51 return None 52 53 ...
創建全新的庫文件:
1 # -*- coding: utf-8 -*- 2 3 from libs.DB_utils.utils import * 4 from libs.request_utils import utils 5 from libs.request_utils import flow_task_manage 6 from libs.global_enum import * 7 from libs.model import user_search_result 8 from robot.libraries.BuiltIn import BuiltIn 9 import time 10 11 12 class VerifyLibrary(object): 13 14 def __init__(self, base_URL, username, dubbo_web_base_URL=None): 15 self.base_URL = base_URL 16 self.username = username 17 self.request_utils = utils.RequestUtil(base_URL, username) 18 self.flow_task_request_utils = flow_task_manage.FlowTaskManage(base_URL, username) 19 self.built_in = BuiltIn() 20 if dubbo_web_base_URL is not None: 21 self.dubbo_web_request_utils = utils.RequestUtil(dubbo_web_base_URL) 22 23 def update_verify_user_role(self, email, dept_id, role_id, amount_limit=5000): 24 real_name = get_verify_user_name_by_email(email) 25 verify_user_id = get_verify_user_id_by_email(email) 26 self.request_utils.login() 27 response = self.request_utils.update_verify_user(real_name, verify_user_id, amount_limit, dept_id, role_id) 28 return response.json()
注意VerifyLibrary的構造函數,需要最少傳入兩個參數,這是在robot文件引用此庫文件的時候傳入的:
RF框架與Jenkins CI集成
使用Jenkins來運行RF寫的test case很簡單,首先需要在Jenkins上安裝RF擴展插件:
然后,使用pybot命令行去運行寫好的RF測試用例:
最后執行完測試后,可以在jenkins上很好的解析出測試結果的走勢與具體的每個build的測試結果: