Python作接口自動化測試框架

框架結構以下:mysql

Test_Api_Project
|
|---base.py
|---base_api
|   |---register_api.pyredis

|   |---send_sms_code_api.py
|---settings.py
|---test_case
|   |---test_register_api.pysql

|---utilities數據庫

|  |---conn_db.pyjson

|  |---user.pyapi

 

1、先說settings配置文件,與WEB端自動化相似,settings文件中存放整個項目的配置,如:被測項目域名、數據庫地址、redis地址、APP版本號、請求頭等。app

# env config
ENV = 'test'

APP_VERSION = '2.3.7'

HEADERS = {'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'}

# test url test config
API_TEST_BASE_URL = "http://api.abc.com"

# redis config
REDIS_HOST = ''
REDIS_PORT = ''

# mysql config
DB_HOST = ''
DB_PORT = ''
DB_USER = ''
DB_PASSWORD = ''

 

2、base.py框架

該文件中主要是對測試url的處理、對經常使用的請求類型從新封裝(如:GET、POST等)ide

# -*- coding:utf-8 -*-
import json,requests
import settings


class BaseApi(object):
    url = ""
    base_url= settings.API_TEST_BASE_URL

    def __init__(self,url_params=None):
        if not url_params:
            url_params = []
        self.url_params = url_params
        self.response = None
        self.base_url = self.base_url

    # 拼接url
    def api_url(self):
        if not self.url:
            raise RuntimeError("no url been set")
        return self._get_url()

    def _get_url(self):
        format_url = self.url.format(self.url_params)
        return "{0}{1}".format(self.base_url, format_url)

    # 封裝POST請求類型
    def post(self, data=None):
        if not data:
            data = {}
        base_param = self.build_base_param()
        custom_param = self.build_custom_param(data)
        data.update(base_param)
        data.update(custom_param)
        self.response = requests.post(url=self.api_url(), data=data, headers=settings.HEADERS)
        return self.response

    # 封裝GET請求類型
    def get(self,data=None):
        if not data:
            data={}
        base_param = self.build_base_param()
        custom_param = self.build_custom_param(data)
        data.update(base_param)
        data.update(custom_param)
        response = requests.get(url=self.api_url(),params=data)
        return self.response

    # 獲取回參中狀態碼
    def get_code(self):
        if self.response:
            return json.loads(self.response.text)['code']

    # 獲取HTTP狀態碼
    def get_status_code(self):
        if self.response:
            return self.response.status_code

    # 獲取回參中message
    def get_response_message(self):
        if self.response:
            return json.loads(self.response.text)['msg']

    # 全部接口共有的入參,好比:app_version、token等
    def build_base_param(self):
        return {
                "app_version": SETTINGS.APP_VERSION,
                "token":""
        }

    # 被測接口除公共參數外所需的其他參數
    def build_custom_param(self, data):
        return {}

 

3、conn_db.py 鏈接數據庫post

import pymysql.cursors,settings


def execute(sql, params=None, db='', is_fetchone=True):
    # Connect to the database
    connection = pymysql.connect(host=settings.DB_HOST,
                                 port=settings.DB_PORT,
                                 user=settings.DB_USER,
                                 password=settings.DB_PASSWORD,
                                 db=db,
                                 autocommit=True,
                                 charset='utf8mb4',
                                 cursorclass=pymysql.cursors.DictCursor)
    try:
        with connection.cursor() as cursor:
            cursor.execute(sql, params)
            if is_fetchone:
                return cursor.fetchone()
            else:
                return cursor.fetchall()
    finally:
        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))

 

 

4、下面以註冊接口爲例子

因註冊時須要獲取短信驗證碼,因此除了調用註冊接口以外,還須要調用獲取短信驗證碼皆苦,在base_api下新建register_api.py、send_sms_code_api.py,內容以下:

register_api.py

# -*- coding:utf-8 -*-
from base_api.base_api import BaseApi
import settings

class RegisterApi(BaseApi):
    url = '/home/register'
    
    #對BaseApi類中build_custom_param方法重寫
    def build_custom_param(self, data):
        return {'login_name':data['login_name'],'password':data['password'],'code':data['code'],'nickname':data['nickname']}

 

send_sms_code_api.py

# -*- coding:utf-8 -*-
from base_api.base_api import BaseApi
import settings


class SendSmsCaptcha(BaseApi):
    url = '/user/sendsms'

    def build_custom_param(self, data):
        return {'type': data['type'], 'phone': data['phone']}

 

對兩個接口的url地址和所須要的入參都已經封裝好了,接下來開始寫case。

 

在test_case下新建test_register_api.py

下面是一個註冊成功的例子

# -*- coding:utf-8 -*-
from unittest import TestCase
from base_api.register_api import RegisterApi
from base_api.send_sms_code_api import SendSmsCaptcha
from utilities import user
import settings,json



class TestRegisterApi(TestCase):
    new_mobile = '13000000001'
    password = '123abc'
    nick_name = 'XiangXi'


    def test_register_success(self):
        # 調用發送短信驗證碼接口
        send_sms_code_api = SendSmsCaptcha()
        send_sms_code_api.post({'type':'register','phone':self.new_mobile})

        # 校驗發送短信驗證碼接口HTTP狀態碼爲200
        self.assertEqual(send_sms_code_api.get_status_code(),200)

        # 校驗發送短信驗證碼接口反參中code爲0,表明成功(不一樣項目該字段值不必定爲0)
        self.assertEqual(send_sms_code_api.get_code(),0)

        # 經過數據庫獲取短信驗證碼
        sms_code = user.get_sms_captcha(self.new_mobile)

        # 調用註冊接口
        register_api = RegisterApi()
        response = register_api.post({'login_name':self.new_mobile,'password':self.password,'code':sms_code,'nickname':self.nick_name})

        # 校驗註冊接口HTTP狀態碼爲200
        self.assertEqual(send_sms_code_api.get_status_code(),200)

        # 校驗註冊接口反參中code爲0
        self.assertEqual(register_api.get_code(),0)

        # 校驗反參中手機號、登陸名與用戶暱稱是否與入參值同樣
        identity_obj = json.loads(response.content)['result']['identity_obj']
        self.assertEqual(identity_obj['nickname'],self.nick_name)
        self.assertEqual(identity_obj['login_name'],self.new_mobile)
        self.assertEqual(identity_obj['mobilephone'],self.new_mobile)

    def tearDown(self):
        user.delete_user(self.new_mobile)

 

 

最後和WEB端相似,經過teardown()方法將新註冊的用戶在數據庫中刪除,防止該手機號下次執行case時候報手機號已被註冊。

爲了更好了驗證經過接口註冊的用戶信息,也能夠調用登陸接口測試一下注冊接口反參中的用戶名是否能夠正常登錄返回token。

 

5、若是調用接口的前提須要用戶登陸,那麼就須要BaseApi類中build_base_param方法中的token有一個有效的值,不然調用接口時可能會提示token錯誤或者用戶未登陸等,這種狀況下能夠新建一個LoginBaseApi類,繼承BaseApi,代碼以下:

假設對登陸接口已經進行了封裝,入參爲login_name和password

# -*- coding:utf-8 -*-
from base_api.base_api import BaseApi
from base_api.login_api import LoginApi

class LoginBaseApi(BaseApi):
    def __init__(self, login_name,password, *args, **kwargs):
        super(LoginBaseApi, self).__init__(*args, **kwargs)
        self.login_name = login_name
        self.password = password

    def build_base_param(self):
        base_param = super(LoginBaseApi, self).build_base_param()
        response = LoginApi().post(self.login_name, self.password)
        base_param['token'] = token
        return base_param

 

 

這時,底層類就有兩個,一個是BaseApi() 一個是LoginBaseApi(),須要登陸的接口在封裝入參時繼承LoginBaseApi,不須要登陸的接口繼承BaseApi

 

不一樣項目接口的入參格式,反參格式可能會不一樣,僅供參考

相關文章
相關標籤/搜索