框架结构如下:
Test_Api_Project
|
|---base.py
|---base_api
| |---register_api.py
| |---send_sms_code_api.py
|---settings.py
|---test_case
| |---test_register_api.py
|---utilities
| |---conn_db.py
| |---user.py
1 # env config 2 ENV = 'test' 3 4 APP_VERSION = '2.3.7' 5 6 HEADERS = {'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'} 7 8 # test url test config 9 API_TEST_BASE_URL = "http://api.abc.com" 10 11 # redis config 12 REDIS_HOST = '' 13 REDIS_PORT = '' 14 15 # mysql config 16 DB_HOST = '' 17 DB_PORT = '' 18 DB_USER = '' 19 DB_PASSWORD = '' |
二、base.py
该文件中主要是对测试url的处理、对常用的请求类型重新封装(如:GET、POST等)
1 # -*- coding:utf-8 -*- 2 import json,requests 3 import settings 4 5 6 class BaseApi(object): 7 url = "" 8 base_url= settings.API_TEST_BASE_URL 9 10 def __init__(self,url_params=None): 11 if not url_params: 12 url_params = [] 13 self.url_params = url_params 14 self.response = None 15 self.base_url = self.base_url 16 17 # 拼接url 18 def api_url(self): 19 if not self.url: 20 raise RuntimeError("no url been set") 21 return self._get_url() 22 23 def _get_url(self): 24 format_url = self.url.format(self.url_params) 25 return "{0}{1}".format(self.base_url, format_url) 26 27 # 封装POST请求类型 28 def post(self, data=None): 29 if not data: 30 data = {} 31 base_param = self.build_base_param() 32 custom_param = self.build_custom_param(data) 33 data.update(base_param) 34 data.update(custom_param) 35 self.response = requests.post(url=self.api_url(), data=data, headers=settings.HEADERS) 36 return self.response 37 38 # 封装GET请求类型 39 def get(self,data=None): 40 if not data: 41 data={} 42 base_param = self.build_base_param() 43 custom_param = self.build_custom_param(data) 44 data.update(base_param) 45 data.update(custom_param) 46 response = requests.get(url=self.api_url(),params=data) 47 return self.response 48 49 # 获取回参中状态码 50 def get_code(self): 51 if self.response: 52 return json.loads(self.response.text)['code'] 53 54 # 获取HTTP状态码 55 def get_status_code(self): 56 if self.response: 57 return self.response.status_code 58 59 # 获取回参中message 60 def get_response_message(self): 61 if self.response: 62 return json.loads(self.response.text)['msg'] 63 64 # 所有接口共有的入参,比如:app_version、token等 65 def build_base_param(self): 66 return { 67 "app_version": SETTINGS.APP_VERSION, 68 "token":"" 69 } 70 71 # 被测接口除公共参数外所需的其余参数 72 def build_custom_param(self, data): 73 return {} |
三、conn_db.py 连接数据库
1 import pymysql.cursors,settings 2 3 4 def execute(sql, params=None, db='', is_fetchone=True): 5 # Connect to the database 6 connection = pymysql.connect(host=settings.DB_HOST, 7 port=settings.DB_PORT, 8 user=settings.DB_USER, 9 password=settings.DB_PASSWORD, 10 db=db, 11 autocommit=True, 12 charset='utf8mb4', 13 cursorclass=pymysql.cursors.DictCursor) 14 try: 15 with connection.cursor() as cursor: 16 cursor.execute(sql, params) 17 if is_fetchone: 18 return cursor.fetchone() 19 else: 20 return cursor.fetchall() 21 finally: 22 connection.close() |
user.py文件主要是对数据库中用户相关的一些操作
# -*- coding:utf-8 -*-
import db
def get_sms_captcha(mobile):
# 获取短信验证码
sms_captcha = db.execute('select code from send_sms_code where mobile=%s order by id desc',params=(mobile))
return sms_captcha['code']
def delete_user(mobile):
# 删除用户
db.execute('delete from user where mobile=%s',params=(mobile))
四、下面以注册接口为例子
因注册时需要获取短信验证码,所以除了调用注册接口之外,还需要调用获取短信验证码皆苦,在base_api下新建register_api.py、send_sms_code_api.py,内容如下:
register_api.py
1 # -*- coding:utf-8 -*- 2 from base_api.base_api import BaseApi 3 import settings 4 5 class RegisterApi(BaseApi): 6 url = '/home/register' 7 8 #对BaseApi类中build_custom_param方法重写 9 def build_custom_param(self, data): 10 return {'login_name':data['login_name'],'password':data['password'],'code':data['code'],'nickname':data['nickname']} |
send_sms_code_api.py
1 # -*- coding:utf-8 -*- 2 from base_api.base_api import BaseApi 3 import settings 4 5 6 class SendSmsCaptcha(BaseApi): 7 url = '/user/sendsms' 8 9 def build_custom_param(self, data): 10 return {'type': data['type'], 'phone': data['phone']} |
对两个接口的url地址和所需要的入参都已经封装好了,接下来开始写case。
在test_case下新建test_register_api.py
下面是一个注册成功的例子
1 # -*- coding:utf-8 -*- 2 from unittest import TestCase 3 from base_api.register_api import RegisterApi 4 from base_api.send_sms_code_api import SendSmsCaptcha 5 from utilities import user 6 import settings,json 7 8 9 10 class TestRegisterApi(TestCase): 11 new_mobile = '13000000001' 12 password = '123abc' 13 nick_name = 'XiangXi' 14 15 16 def test_register_success(self): 17 # 调用发送短信验证码接口 18 send_sms_code_api = SendSmsCaptcha() 19 send_sms_code_api.post({'type':'register','phone':self.new_mobile}) 20 21 # 校验发送短信验证码接口HTTP状态码为200 22 self.assertEqual(send_sms_code_api.get_status_code(),200) 23 24 # 校验发送短信验证码接口反参中code为0,代表成功(不同项目该字段值不一定为0) 25 self.assertEqual(send_sms_code_api.get_code(),0) 26 27 # 通过数据库获取短信验证码 28 sms_code = user.get_sms_captcha(self.new_mobile) 29 30 # 调用注册接口 31 register_api = RegisterApi() 32 response = register_api.post({'login_name':self.new_mobile,'password':self.password,'code':sms_code,'nickname':self.nick_name}) 33 34 # 校验注册接口HTTP状态码为200 35 self.assertEqual(send_sms_code_api.get_status_code(),200) 36 37 # 校验注册接口反参中code为0 38 self.assertEqual(register_api.get_code(),0) 39 40 # 校验反参中手机号、登录名与用户昵称是否与入参值一样 41 identity_obj = json.loads(response.content)['result']['identity_obj'] 42 self.assertEqual(identity_obj['nickname'],self.nick_name) 43 self.assertEqual(identity_obj['login_name'],self.new_mobile) 44 self.assertEqual(identity_obj['mobilephone'],self.new_mobile) 45 46 def tearDown(self): 47 user.delete_user(self.new_mobile) |
最后和WEB端类似,通过teardown()方法将新注册的用户在数据库中删除,防止该手机号下次执行case时候报手机号已被注册。
为了更好了验证通过接口注册的用户信息,也可以调用登录接口测试一下注册接口反参中的用户名是否可以正常登陆返回token。
五、如果调用接口的前提需要用户登录,那么就需要BaseApi类中build_base_param方法中的token有一个有效的值,否则调用接口时可能会提示token错误或者用户未登录等,这种情况下可以新建一个LoginBaseApi类,继承BaseApi,代码如下:
假设对登录接口已经进行了封装,入参为login_name和password
1 # -*- coding:utf-8 -*- 2 from base_api.base_api import BaseApi 3 from base_api.login_api import LoginApi 4 5 class LoginBaseApi(BaseApi): 6 def __init__(self, login_name,password, *args, **kwargs): 7 super(LoginBaseApi, self).__init__(*args, **kwargs) 8 self.login_name = login_name 9 self.password = password 10 11 def build_base_param(self): 12 base_param = super(LoginBaseApi, self).build_base_param() 13 response = LoginApi().post(self.login_name, self.password) 14 base_param['token'] = token 15 return base_param |
这时,底层类就有两个,一个是BaseApi() 一个是LoginBaseApi(),需要登录的接口在封装入参时继承LoginBaseApi,不需要登录的接口继承BaseApi
不同项目接口的入参格式,反参格式可能会不同,仅供参考
上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。