自動化介面測試
1.主要策略:
response = requests.request(method=method, url=url, data=params, files=files, headers=headers, verify=False) response_date = { "status_code": str(response.status_code), "reason": response.reason, "success": json.loads(response.text)['success'],"msg": json.loads(response.text)['msg'] }
上述程式碼呼叫Python的 requests庫 函式 request:構造一個請求,支撐一下方法的基礎方法。用函式 request封裝的方法請求一個介面(帶引數)返回的資料作為【實際值】,由此對【期望值】--進行【斷言判斷】;
第一步先判斷該介面是否可用,也就是先判斷返回的狀態碼是否為:200,然後判斷是否包含【期望有的】關鍵字,對期望有的關鍵字進行賦值,賦值後再作為一個數組返回--出參;這一步是函式api_connection實現的,主要出參就是後期用於做斷言判斷是---【實際值】;
2.測試結果校驗主函式:
def assert_response(self, response_data, params=None, exp_status_code='200', exp_reason='OK', exp_success=True, exp_msg=None): if params != None: robot.api.logger.info("入參: %s" % params) #robot.api.logger.info("返回值: %s" % response_data) robot.api.logger.info("校驗:status_code 期望值: %s 實際值:%s " % (exp_status_code, response_data['status_code'])) robot.api.logger.info("校驗:reason 期望值:%s 實際值:%s " % (exp_reason, response_data['reason'])) robot.api.logger.info("校驗:success 期望值:%s 實際值:%s " % (exp_success , response_data['success'])) if exp_msg != None : robot.api.logger.info("校驗:msg 期望值:%s 實際值:%s " % (exp_msg , response_data['msg'])) assert_true(response_data['msg'] == exp_msg, "msg錯誤!") assert_true(response_data['status_code'] == exp_status_code, "status_code錯誤!") assert_true(response_data['reason'] == exp_reason, "reason錯誤!") assert_true(response_data['success'] == exp_success, "success錯誤!")
上述程式碼主要實現,判斷【期望值】與【實際值】是否相符合,所謂【期望值】就是測試人員自己設想的應該有的值,不參考實際值。呼叫了函式assert_true進行斷言
3.實現發起http連線請求的主函式:
def api_connection(self, suburl, headers, method="POST", params=None, files=None): url = "https://ci-its.chinanetcenter.com" + suburl robot.api.logger.info("介面: %s" % url) response = requests.request(method=method, url=url, data=params, files=files, headers=headers, verify=False) response_date = { "status_code": str(response.status_code), "reason": response.reason, "success": json.loads(response.text)['success'], "msg": json.loads(response.text)['msg'] } if response.status_code == 200: if json.loads(response.text).has_key('success'): response_date['success'] = json.loads(response.text)['success'] else: response_date['success'] = None if json.loads(response.text).has_key('data'):response_date['data'] = json.loads(response.text)['data'] //這一步至關重要 else: response_date['data'] = None if json.loads(response.text).has_key('msg'): response_date['msg'] = json.loads(response.text)['msg'] if json.loads(response.text).has_key('exception'): response_date['exception'] = json.loads(response.text)['exception'] return response_date
第一步先判斷該介面是否可用,也就是先判斷返回的狀態碼是否為:200,然後判斷是否包含【期望有的】關鍵字,對期望有的關鍵字進行賦值,賦值後再作為一個數組返回--出參;這一步是函式api_connection實現的,主要出參就是後期用於做斷言判斷是---【實際值】;
4.實現post傳送用於測試的請求資料的主函式:
def api_post(self, api_url, cookie, content_type=None, headers_add=None, params=None, exp_status_code='200', exp_reason='OK', exp_success=True, exp_msg=None): if content_type == "application/json;charset=UTF-8": params = json.dumps(params) headers = { 'content-type': content_type, 'cookie': cookie } if headers_add is not None: headers.update(headers_add) robot.api.logger.info("headers: %s " % headers) response_data = self.api_connection(api_url, headers=headers, params=params)
//這裡呼叫了發起連線請求的函式 self.assert_response(params=params, response_data=response_data, exp_status_code=exp_status_code, exp_reason=exp_reason, exp_success=exp_success, exp_msg=exp_msg) //這裡其實呼叫了進行斷言判斷的主函式
return response_data
5.實現get獲取介面資料的主函式:
def api_get(self, api_url, cookie, exp_status_code='200', exp_reason='OK', exp_success=True): headers = { 'cookie': cookie } response_data = self.api_connection(api_url, method="GET",headers=headers) self.assert_response(response_data=response_data, exp_status_code=exp_status_code, exp_reason=exp_reason, exp_success=exp_success) return response_data
6.實際介面測試的情況分為兩步:
(1)只測試介面返回http狀態的:
import ApiLib class ProblemLib(ApiLib.ApiLib): ROBOT_LIBRARY_SCOPE = 'GLOBAL' ROBOT_LIBRARY_VERSION = "0.1" //下邊的兩個函式只實現了校驗介面返回狀態,並沒有校驗返回資料是否和資料庫一致 def problem_problemQuery(self, **params): api_result = self.api_post(api_url="/problem/problemQuery.action", cookie=self.cookie, content_type="application/x-www-form-urlencoded; charset=UTF-8", params=params) def problem_completeList(self, **params): api_result = self.api_post(api_url="/problem/completeList.action", cookie=self.cookie, content_type="application/x-www-form-urlencoded; charset=UTF-8", params=params)
這邊的介面的入參主要通過Robot FrameWork組織起來的,也就是各種入引數據(業務場景=測試用例),如下:
(2)對返回資料進行校驗,主要通過sql語句查詢資料庫獲取返回結果,進行斷言判斷
# -*- coding=utf-8 -*- import ApiLib, uuid import robot.api from robot.utils.asserts import assert_true
def custman_to_duty_flow(self, **params): id = self.duty_save(params); //提供其他函式獲取自動生成的id sen = "SELECT DUTY_SN FROM ci_duty WHERE ID = '%s' " % (id) sql_result = self.query_all(sen) //支援該函式可以執行的檔案是SqlLib.py檔案,該檔案中定義的資料庫相關的函式 list_params = { "start": 0, "limit": 10, "pageIndex": 0, "dutyTabFilterEnum": "ALL", "type":"", "description": "", "customerName":"", "priority":"", "status":"", "dutySn": sql_result['DUTY_SN'], "createUser": "", "respondUser": "", "startTime": "", "endTime": "" } step1_result = self.duty_list(list_params) //通過其他函式(介面)獲取實際返回值 assert_true(step1_result['DUTY_SN'] == exp_msg, "xiangmu中文") self.duty return params['id']
上述程式碼呼叫到的其他函式有:
1.自動獲取生成ID的函式:duty_save(params)
def duty_save(self, **params): params['id'] = str(uuid.uuid1()) api_result = self.api_post(api_url="/duty/save.action", cookie=self.cookie, content_type="application/x-www-form-urlencoded; charset=UTF-8", params=params) return params['id']
2.用於提交介面測試引數的前置步驟:duty_list(list_params)
def duty_list(self, **params): api_result = self.api_post(api_url="/duty/list.action", cookie=self.cookie, content_type="application/x-www-form-urlencoded; charset=UTF-8", params=params)
這種函式對應的入引數據,也是在RobotFrameWork指令碼中構造的,和上面的圖片類似的結構;
3.資料庫相關的函式支援:
# -*- coding=utf-8 -*- import pymysql, datetime, robot.api from decimal import Decimal class SqlLib(): ROBOT_LIBRARY_SCOPE = 'GLOBAL' ROBOT_LIBRARY_VERSION = "0.1" CONNECTION = { 'host': "*******", 'port': ******, 'user': '******', 'password': '********', 'db': '*****', 'charset': 'utf8' } def _database_connect(self): self.__db = pymysql.connect( **SqlLib.CONNECTION) self.cursor = self.__db.cursor(cursor=pymysql.cursors.DictCursor) def database_close(self): self.__db.close() def query_one(self, sql_sen): self._database_connect() self.cursor.execute(sql_sen) result = { 'sql': sql_sen, 'count': str(self.cursor.rowcount), 'data': self.cursor.fetchone() } return result //這個函式就是上文提到的用於支援測試資料庫中資料是否和實際返回資料一致的函式 def query_all(self, sql_sen): robot.api.logger.info(u"SQL語句: %s" % sql_sen) self._database_connect() self.cursor.execute(sql_sen) result = { 'sql': sql_sen, 'count': str(self.cursor.rowcount), 'data': self.cursor.fetchall() } robot.api.logger.info(u"查詢結果:%s " % result) return result