自动化接口测试
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语句查询数据库获取返回结果,进行断言判断
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