Python 接口自动化测试框架和用例实践

结构介绍

先来看下大体结构:

1、总体结构

2、细分结构

2.1、conf(全局变量)

2.2、cases(测试用例)

2.3、日志和报告

2.4、tools(通用工具模块)

2.5、core (代码模块)

2.6、bin(执行模块)

2.7、api_verify(单接口测试模块)

模块介绍

1、conf(全局变量)

所有得通用得变量都可以放在这里面,代码如下,大家一看就明白,不用多说了。

# -*- coding:utf-8 -*-
"""
全局变量
"""
import os

BASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
LOG_PATH = os.path.join(BASE_PATH, 'logs')  # log的路径
REPORT_PATH = os.path.join(BASE_PATH, 'report')  # 报告的路径
CASE_PATH = os.path.join(BASE_PATH, 'cases')  # 用例的存放路径
CORE_CASE_PATH = os.path.join(BASE_PATH, 'bin')  # 生成的用例的存放路径
CORE_CASE_PATH1 = os.path.join(BASE_PATH, 'api_verify')  # 生成的用例的存放路径
FILE_PATH = os.path.join(BASE_PATH,'core')
SFZ_PATH = os.path.join(BASE_PATH,'tools')
PHONENUMBER = '18500000020'
OLDPHONENUMBER = '18601337379'
PAYMENTPASSWORD1 ='111111'
PACKAGENAME = 'com.laijin.simplefinance'
USERAGENT = 'Mozilla/5.0 (Linux; U; Android 8.1.0; zh-cn; PACM00 Build/O11019) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30'
SCHEME = 'http'
SCHEME_s = 'https'
CREDITCARD_IDNO = 110101198501010076
# 信用卡绑卡身份证号
CREDITCARD_NO = 6225757520003932
# 信用卡卡号
# HOST = '10.103.27.11:8081'
API_HOSTS = {
        'test1':'qa-api.jilc.com',
        'test2':'qb-api.jilc.com',
        'test3':'qc-api.jilc.com',
        'test4':'qd-api.jilc.com',
        'snb_test':'10.113.20.23:8080'
}

HOST = 'qa-api.jilc.com'
mysql_envs={
        'test1':{
                'HOST':'10.108.27.14',
                'modify_zk_port':'9002',
                'db':{
                        'PORT':3306,
                        'MYSQLDB':'test1_product',
                        'MYSQLUSER':'root',
                        'MYSQLPASSWORD':'123123'
                }
        },
        'test2':{
                'HOST':'10.108.27.14',
                'modify_zk_port':'9003',
                'db':{
                        'PORT':3306,
                        'MYSQLDB':'test2_product',
                        'MYSQLUSER':'root',
                        'MYSQLPASSWORD':'123123'
                }
        },
        'test3':{
                'HOST':'10.108.27.14',
                'modify_zk_port':'9004',
                'db':{
                        'PORT':3306,
                        'MYSQLDB':'test3_product',
                        'MYSQLUSER':'root',
                        'MYSQLPASSWORD':'123123'
                }
        },
        'test4':{
                'HOST':'10.108.27.14',
                'modify_zk_port':'9005',
                'db':{
                        'PORT':3306,
                        'MYSQLDB':'test4_product',
                        'MYSQLUSER':'root',
                        'MYSQLPASSWORD':'123123'
                }
        },
        'snb_test':{
                'HOST':'10.108.27.14',
                'modify_zk_port':'8080',
                'db':{
                        'PORT':3306,
                        'MYSQLDB':'dev1_fund',
                        'MYSQLUSER':'root',
                        'MYSQLPASSWORD':'123123'
                }
        }
}
ATHCODE ='123456'
LoginPassWord = 'abcd1234'
FALSEATHCODE = '654321'
SIGNKEY ='qwrobxkjlertty12edwsvfc@22#%^db'
BANKCARDPRENUM ='6225880155896666665'
# BANKCARDPRENUM ='622848'
PAYMENTPASSWORD ='123456'
CREDIT_CARD_NUMBER ='552599'
BANKSIMPLECODE_NYYH ='CMB'
BANKSIMPLECODE_HXYH ='HXB'
BANK_ID ='101'
BANK_NAME ='招商银行'
BANK_NAME_HXYY ='华夏银行'
WRONG_CARD_NUM ='622588015589666666'
AESKEY ='xvX7%l[K*lBRRX7!'
AESIV ='3293952646531178'
BANK_CARD_ROUTE_CHANNEL = 5
# 3:民生。5:通付盾
MAXWITHDRAWAMOUNT = 50000

1.2、cases(测试用例)

当然,代码里面得很多得配置都可以拿到表格中配置,比如:接口名称,参数等。

但是排列不能乱,需要对应取值得。

ID 用例编号 版本 模块 功能 前提条件 操作步骤 预期结果 调用方法
1 snb_Entrance_1 拾年宝 拾年宝入口 拾年宝入口是否正常 拾年宝入口进入 正常进入 正常进入 self.base.snb_list_Entrance
2 snb_FrontPage_1 拾年宝 拾年宝首页 拾年宝首页是否正常 进入到拾年宝首页 正常进入 显示正常 self.base.snb_front_page
3 snd_register_1 拾年宝 注册 注册功能是否正常 未注册的手机号 1.输入手机号,点击注册
2.输入验证码,点击注册
注册成功 self.base.snd_register

1.3、日志和报告

打印日志和存放报告得地方

日志:

可以根据自己得需求,添加或者减少打印信息

报告:

同样,可以根据自己得需求,添加或者减少生成的报告的信息

 1.4、tools(通用工具模块)

通用的工具函数可以放在这里

比如连接数据库的:

class OpMysql(object):
    def __init__(self,host, users, password, port, db):
        self.host=host
        self.users=users
        self.password = password
        self.port=port
        self.db=db
    def connect_mysql(self):
        try:
            conn = pymysql.connect(host=self.host, user=self.users, password=self.password, port=self.port,
                                               db=self.db, charset='utf8')
            conn._write_timeout = 10000
            # cursor = conn.cursor()
            return conn
        except Exception as e:
            w.write_log('数据库连接错误' + str(e))

    def close_mysql(self):
        conn= self.connect_mysql()
        cursor = conn.cursor()
        cursor.close()
        conn.close()

    def op_db_delete(self,sql):
        conn = self.connect_mysql()
        cursor = conn.cursor()
        try:
            print ('delsql',sql)
            cursor.execute(sql)
        except Exception as e:
            w.write_log('sql异常' + str(e))
            return e
        else:
            conn.commit()
            res='数据库删除成功'
            print ('数据库删除成功')
        return res

    def op_db_select(self,sql):
        conn = self.connect_mysql()
        cursor = conn.cursor()
        try:
            print (sql)
            cursor.execute(sql)
        except Exception as e:
            w.write_log('sql异常' + str(e))
            return e
        else:
            res_list = []
            sql_res = cursor.fetchall()
            print ('数据库查询成功')
            # self.conn.cursor(0)         #移动游标
            for c in sql_res:
                res_list.append(c)
        return res_list

    def op_db_update(self,sql):
        # self.cursor = self.conn.cursor()
        conn = self.connect_mysql()
        cursor = conn.cursor()
        try:
            print ('update sql...',sql)
            cursor.execute(sql)
        except Exception as e:
            w.write_log('sql异常' + str(e))
            return e
        else:
            conn.commit()
            res = '数据库修改成功'
            print ('数据库修改成功')
            return res

    def op_db_insert(self,sql):
        conn = self.connect_mysql()
        cursor = conn.cursor()
        try:
            print ('update sql...', sql)
            cursor.execute(sql)
        except Exception as e:
            w.write_log('sql异常' + str(e))
            return e
        else:
            conn.commit()
            res = '数据库添加成功'
            print ('数据库添加成功')
            return res

又比如自动生成手机号和RSA加密的:

class General_Tools(object):
    def createphones(self):
        prelist = ["130", "131", "132", "133", "134", "135", "136", "137", "138", "139", "147", "150", "151", "152",
                   "153", "155", "156", "157", "158", "159", "186", "187", "188"]
        return random.choice(prelist) + "".join(random.choice("0123456789") for i in range(8))
    def rsanumber(self, tokenkey):
        """rsa加密"""
        url = 'http://10.107.24.198:5088/?method=rsaNumber&token=%s' % tokenkey
        response = urllib2.urlopen(url)
        html = response.read()
        print (html)
        return html

这里就不过多的介绍了

1.5、core (代码模块)

这个是重点,需要详细介绍的。

1.5.1、api_request.py

get请求:

class ApiRequest(object):
    def __init__(self,api_host):#等进行实例化的时候,传入api_host
        self.api_host=api_host

    """
    定义函数 需要传入api和params两个参数
    api举例就是host后面的内容,比如:/user/regOrLoginSms/verify
    params就是指的参数了
    """
    def get_api_request(self,api,params,scheme=SCHEME):
        """get请求接口"""
        url = "%s://%s%s" % (scheme, self.api_host, api)#url由三部分组成,http或者https,host,api
        headers = {"Content-Type": "application/gzip+encrypt+json",
                   "Accept-Encoding": "gzip",
                   "User-Agent": "Android_jianlicai"
                   }
        r = requests.get(url,params,headers=headers,verify=False,timeout=10)#requests模块的get方法,timeout是超时时间,单位是秒
        requests.adapters.DEFAULT_RETRIES = 10#设置重新连接的次数,大于会报错
        if r.status_code==200: #获取响应的状态码
            data = json.dumps(r.json(), ensure_ascii=False)
            # 响应回来的是<dict>
            # <dict>和<json>之间的转换
            # <json> = json.dumps(<dict>)
            # <dict> = json.loads(<json>)
            return data
        else:
            w.write_log('服务器状态有误' + '状态码:' + str(r.status_code))#写log

post请求:和get不同的是requests的方法不同,用到的是requests.post

    def post_api_request(self,api,params,scheme=SCHEME):

        """post请求接口"""

        url="%s://%s%s"%(scheme,self.api_host,api)
        headers = {"Content-Type": "application/json",
                   # headers = {"Content-Type": "application/json",
                   "Accept-Encoding": "gzip",
                   "User-Agent": STATISTICS
                   }
        try:
            r = requests.post(url, data=json.dumps(params), headers=headers, verify=False, timeout=100)
        except Exception as e:
            print e
            w.write_log('异常情况:' + str(e))
            return '不通过'
        else:
            requests.adapters.DEFAULT_RETRIES = 10
            if r.status_code==200:
                try:
                    data=json.dumps(r.json(),ensure_ascii=False)
                except Exception as e:
                    w.write_log('异常情况:' + str(e))
                else:
                    return data
            else:
                w.write_log('服务器状态有误'+'状态码:'+str(r.status_code))

1.5.2、base_api_request.py

此模块主要是编写出所有的接口。

这个是重中之重,详细介绍。

在这里拿注册功能,包括三个接口做下说明:

1.输入手机号码点击注册,接口名称:snb_regOrLoginSms_Get

2.输入手机验证码点击注册,接口名称:snb_regOrLoginSms_verify

3.设置登录密码,接口名称:/user/confirmPassword/toRegister

class BaseApiRequest(object):
    """开始编写所有的接口"""

    def __init__(self, op_mysql, api_request):#实例化的时候传入op_mysql,api_request
        self.op_mysql = op_mysql
        self.api_request = api_request


    def snb_regOrLoginSms_Get(self):

        """注册界面,输入手机号,点击注册按钮"""
        """正常接口参数"""
        name = "注册界面,输入手机号,点击注册按钮"
        api_url = '/user/regOrLoginSms/Get'
        phonenumber = general_tools.createphones()#用到前面提到的生成手机号码的工具函数
        params = {"userPhone": phonenumber, "type": 0}

        """接口返回值"""
        response_json_data = self.api_request.post_api_request(api_url,params)
        response_json_data = json.loads(response_json_data)#将返回的json转换成字典,用于后面在字典中的取值


        """判断接口正常状态"""
        api_status, error = general_tools.check_response(name, response_json_data, 0)#调用前面提到的判断接口状态的函数
        print ("接口名:%s,接口描述:%s,error值:%s,状态:%s" % (api_url, name, error, api_status))

        return name, api_url, params, error, api_status, response_json_data,phonenumber#这里的phonenumber用于下一个接口使用

    def snb_regOrLoginSms_verify(self,phonenumber):#phonenumber用到上一个接口返回的手机号码

        """注册界面,输入验证码,点击注册按钮"""
        """正常接口参数"""
        name = "注册界面,输入验证码,点击注册按钮"
        api_url = '/user/regOrLoginSms/verify'
        params = {"userPhone":phonenumber,"smsCode":ATHCODE,"type":0,"wxopenId":"","source":""}#smsCode是在全局变量中配置的短信验证码

        """接口返回值"""
        response_json_data = self.api_request.post_api_request(api_url,params)
        response_json_data = json.loads(response_json_data)
        userId= response_json_data["data"]["userId"]#从返回值中取出来,用于下一个函数
        token = response_json_data["data"]["token"]#从返回值中取出来,用于下一个函数


        """判断接口正常状态"""
        api_status, error = general_tools.check_response(name, response_json_data, 0)
        print ("接口名:%s,接口描述:%s,error值:%s,状态:%s" % (api_url,name, error, api_status))

        return name, api_url, params, error, api_status, response_json_data,userId,token#返回userId,token用于下一个接口使用


    def snb_confirmPassword_toRegister(self,userId,token):

        """注册,设置登陆密码"""
        """正常接口参数"""
        name = "注册界面,输入验证码,点击注册按钮"
        api_url = '/user/confirmPassword/toRegister'
        params = {"userId":userId,"token":token,"smsToken":"","loginPassWord":LoginPassWord,"repeatLoginPassWord":LoginPassWord,"type":0}

        """接口返回值"""
        response_json_data = self.api_request.post_api_request(api_url,params)
        response_json_data = json.loads(response_json_data)


        """判断接口正常状态"""
        api_status, error = general_tools.check_response(name, response_json_data, 0)
        print ("接口名:%s,接口描述:%s,error值:%s,状态:%s" % (api_url,name, error, api_status))

        return name, api_url, params, error, api_status, response_json_data


   

1.5.3、flowcase.py

此模块的主要功能是把base_api_request.py模块的功能,组合起来,形成测试用例。这里面的用例只包含正常的逻辑。也就是说所有的接口的参数都是正常值,不包含非正常值的测试。那么问题来了,为什么要单独测试那?因为如果全部放在flowcase.py中测试,代码量会很多,不好维护;对于接口的非正常值得处理怎么测试那?后面会讲到。

重中之更重!!!

class Flowcase_Function(object):


    def __init__(self, op_mysql, base_api_request, api_request, modify_zk_port):
        self.op_mysql = op_mysql
        self.base_api_request = BaseApiRequest(op_mysql,api_request)
        self.api_request = api_request
        self.modify_zk_port = modify_zk_port
        print 'run.......'
        """主要流程"""
    def snd_register(self, *args):#命名注册函数,用于测试注册相关的接口

        """注册"""
        
        case_id = args[0]
        detail = args[4]
        project = args[2]
        caseSummary = args[4]
        model = args[3]
        #上面这些变量在后面的时候会明白,就是获取的生成的测试用例中的变量

        name,api_url,params,error,api_status,response_json_data,phonenumber = self.base_api_request.snb_regOrLoginSms_Get()#注册相关的第一个接口,并把返回值赋值给变量
        name,api_url,params,error,api_status,response_json_data,userId,token = self.base_api_request.snb_regOrLoginSms_verify(phonenumber)#注册相关的第二个接口,并把返回值赋值给变量
        name,api_url,params,error,api_status,response_json_data = self.base_api_request.snb_confirmPassword_toRegister(userId,token)#注册相关的第三个接口,并把返回值赋值给变量
        #接口名称,接口URL,参数,error值,接口是否通过,接口返回信息
        if api_status == '通过':
            w.write_log(api_url + '\t' + '用例验证通过.' + name + '\n')
            my_sql_result = ''
            status = "通过"
            dic_case = general_tools.op_reseponse_data(api_url, params, case_id,response_json_data,detail,my_sql_result, status,project,caseSummary,model)#op_reseponse_data函数看下面的代码
            return dic_case #返回值主要用于生成测试报告使用

        else:
            # 返回值为空的时候
            w.write_log(api_url + '\t' + '用例验证未通过!' + name + '\n')
            my_sql_result = json.dumps(response_json_data, ensure_ascii=False)
            status = "不通过"
            dic_case = general_tools.op_reseponse_data(api_url, params, case_id,response_json_data,detail,my_sql_result, status,project,caseSummary,model)
            return dic_case

下面分析下上面说的op_reseponse_data函数:

    def op_reseponse_data(self,api_url,params,case_id,response_json_data, detail,status="不通过",my_sql_result='',*args):
        res_list1 = []
        report_dic1 = {
            "url": api_url,
            "request": params,
            "response": response_json_data
        }
        res_list1.append(report_dic1)
        print (res_list1)
        dic_case = {
            "case_id": case_id,
            "project": args[0],#*agr上面函数传入的三个参数project,caseSummary,model取值
            "model": args[-1],
            "detail": args[2],
            "caseSummary": args[-2],
            "my_sql_result":status,
            "status": my_sql_result ,
            "responseDetial": res_list1
        }
        return dic_case

1.5.4、create_case.py

用于通过读取用例表格形成测试用例描述文件。

class GenCasePy(object):
    def __init__(self, case_file, case_name):
        '''
        :param case_file: excel文件名
        :param case_name: 生成的文件名,例如Case_reg
        '''
        self.case_file = case_file
        self.case_name = case_name

    def create_case_file(self):

        """读取excel,形成测试用例"""

        book = xlrd.open_workbook(self.case_file)#打开文件
        sheet = book.sheet_by_index(0)#第一个sheet
        all_case = []  # 存放所有用例
        for line in range(1,sheet.nrows):#读行       sheet.nrows
            case = {}  # 每条用例
            temp = sheet.row_values(line)#获取每行的内容,形成列表,为下面的取值准备
            case['ID'] = int(temp[0])
            case['case_id'] = temp[1].encode('utf-8')
            case['app_version'] = temp[2].encode('utf-8')
            case['title'] = temp[3].encode('utf-8')
            case['detail'] = temp[4].encode('utf-8')
            case['def']=temp[8].encode('utf-8')
            case['step'] = temp[6].encode('utf-8').replace('\n', '')
            all_case.append(case)#读一行加一行
        return all_case

    def create_py_file(self):
        
        """把测试用例写进文件,形成一个py文件,一个测试用例代表一个函数"""

        all_case_fun = '''
#coding=utf-8
import os,sys
reload(sys)
sys.setdefaultencoding('utf-8')
class %s(object):
    def __init__(self,base):
        self.base=base
''' % self.case_name
        all_case = self.create_case_file()
        for case in all_case:
            case_fun = '''
    def {case_id}(self,*arg,**kwargs):
        ID = "{ID}"
        case_id = "{case_id}"
        app_version = "{app_version}"
        title = "{title}"
        detail = "{detail}"
        step = "{step}"
        return {def}(ID,case_id,app_version,title,detail,step)
            '''.format(**case)
            all_case_fun += case_fun
        fw = open(CORE_CASE_PATH +'/'+ self.case_name + '.py', 'w')
        fw.write(all_case_fun)

case_pyfile = GenCasePy(os.path.join(CASE_PATH, 'TestCase.xlsx'), 'snb_case')

case_pyfile.create_py_file()

运行上面的代码,会生成snb_case.py文件,内容如下:

class snb_case(object):
    def __init__(self,base):
        self.base=base
            
    def snd_register_1(self,*arg,**kwargs):
        ID = "3"
        case_id = "snd_register_1"
        app_version = "拾年宝"
        title = "注册"
        detail = "注册功能是否正常"
        step = "1.输入手机号,点击注册2.输入验证码,点击注册"
        return self.base.snd_register(ID,case_id,app_version,title,detail,step)
        #调用flowcase.py中snb_register函数返回用例测试数据

到此为止,用例写完了,要执行用例了。

1.6、bin(执行模块)

1.6.1、snb_start.py

前面我们讲了各个部分,但是在这里,在这个执行文件中,才会真正得把流程得顺序和需要传入得参数都表示出来。把这个看明白了,自然也就会理解上面得那些模块了。因为这里用到了上面所有得模块。

import sys, os,socket,time
# from core.flowcase import base
base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(base_path)
reload(sys)
sys.setdefaultencoding('utf-8')
from core.create_case import case_pyfile
from core.snb_report import HtmlReport
from tools.tools import OpMysql
from core.flowcase import Flowcase_Function
from core.base_api_request import BaseApiRequest
from conf import settings
from core.api_request import ApiRequest
from core.sendmail import SendMail


#判断是否是在本地运行,如果在本地运行,选择test1
if socket.gethostname().startswith('DESKTOP'):#判断是不是在我本机上执行得,如果是就获取固定得api_host和数据库对应的相关的信息
    env='snb_test'
    version='拾年宝'
    api_host=settings.API_HOSTS.get(env)#获取host
    # settings.HOST = settings.HOSTS.get(env)
    host = settings.mysql_envs.get(env).get('HOST')#获取host获取数据的IP地址
    #获取数据库的信息
    users = settings.mysql_envs.get(env).get('db').get('MYSQLUSER')
    password = settings.mysql_envs.get(env).get('db').get('MYSQLPASSWORD')
    port = settings.mysql_envs.get(env).get('db').get('PORT')
    db = settings.mysql_envs.get(env).get('db').get('MYSQLDB')
    modify_zk_port=settings.mysql_envs.get(env).get('modify_zk_port')
    #modify_zk_root = settings.mysql_envs.get(env).get('modify_zk_root')
else:
    #执行start.py的时间,后面需要跟一个参数,这个参数是test*,从而获取到测试环境
    #执行的时候的命令是在交互模式下,输入命令:python snb_start.py test1,则argv[1]对应的就是测试1的环境,就获取到测试1的api_host和数据库对应的相关的信息
    env = sys.argv[1]
    # test1,test2,test3,test4
    api_host=settings.API_HOSTS.get(env)
    host=settings.mysql_envs.get(env).get('HOST')
    users=settings.mysql_envs.get(env).get('db').get('MYSQLUSER')
    password=settings.mysql_envs.get(env).get('db').get('MYSQLPASSWORD')
    port = settings.mysql_envs.get(env).get('db').get('PORT')
    db = settings.mysql_envs.get(env).get('db').get('MYSQLDB')
    modify_zk_port=settings.mysql_envs.get(env).get('modify_zk_port')
    modify_zk_root = settings.mysql_envs.get(env).get('modify_zk_root')
    version = sys.argv[2]#同上,执行start.py的时间,后面第二个参数,也就是版本信息
# op_mysql = OpMysql(host,users,password,db,port)
op_mysql = OpMysql(host,users,password,port,db)  #连接数据库的




case_pyfile.create_py_file()#生成测试用例的.py文件
from snb_case import snb_case
api_request=ApiRequest(api_host)#实例化ApiRequest类
base_api_request = BaseApiRequest(op_mysql,api_request)#实例化baseApiRequest类


start_time=time.time()
if version=='拾年宝':
    basecase = Flowcase_Function(op_mysql, base_api_request, api_request, modify_zk_port)#测试用例实例化
    base_reg = snb_case(basecase)#生成的测试用例实例化  basecase == base
    case_1 = base_reg.snb_Entrance_1()
    case_2 = base_reg.snb_FrontPage_1()
    case_3 = base_reg.snd_register_1()

    #生成报告信息
    case_list = []
    case_list.append(case_1)
    case_list.append(case_2)
    case_list.append(case_3)

end_time=time.time()

# 以下是生成的报告内容
op_mysql.close_mysql()
# 关闭数据库
all = {}
total = len(case_list)
all['all']=total    #用例总数
pass_count = 0  #通过的次数

for r in case_list:
        if r['status']=='通过':
                pass_count+=1
all['ok'] = pass_count#通过的次数
all['fail'] = total-pass_count#失败的次数
all['run_time'] = end_time-start_time
all['case_res']=case_list
report = HtmlReport(all)#实例化产生html类的对象
html_name = report.report()#调用生成html的方法,它返回报告的名字
title = time.strftime('%Y%m%d%H%M%S') + '接口测试报告'
content = '本次运行%s条用例,通过%s条,失败%s条。'%(total,pass_count,total-pass_count)

至此,就完成了,上面说过,至于单接口的测试(异常情况的测试怎么进行),下面就开始说。

1.7、api_verify(单接口全覆盖测试)

和上面的测试用例一样,会共用api_request.py模块,setting.py模块。

1.7.1、base_api_request_single_verify.py

    def snb_regOrLoginSms_Get(self,*args):

        """注册界面,输入手机号,点击注册按钮"""

        case_id = args[1]
        detail = args[4]
        project = args[2]
        caseSummary = args[5]
        model = args[3]
        i = args[6]  #取值index

        name = "注册界面,输入手机号,点击注册按钮"
        api_url = '/user/regOrLoginSms/Get'
        phonenumber = general_tools.createphones()
        #用列表的形式,列出所有的参数的组合
        params = [{"userPhone": phonenumber, "type": 0},{"userPhone": "1500103256", "type": 0},{"userPhone": phonenumber, "type": 1}]

        """根据接口开发的定义自行进行判断"""
        if i == 0:
            except_error_code = 0
            response_json_data = self.api_request.post_api_request(api_url,params[i])
            response_json_data = json.loads(response_json_data)
        elif i == 1:
            except_error_code = 10003
            response_json_data = self.api_request.post_api_request(api_url, params[i])
            response_json_data = json.loads(response_json_data)
        elif i == 2:
            except_error_code = 100117
            response_json_data = self.api_request.post_api_request(api_url, params[i])
            response_json_data = json.loads(response_json_data)

            """判断接口状态"""
        api_status, error = general_tools.check_response(name, response_json_data, except_error_code)
        print ("接口名:%s,用例ID:%s,接口描述:%s,error值:%s,状态:%s" % (api_url,case_id, name, error, api_status))

        if api_status == '通过':
            w.write_log(case_id + '\t' + '接口验证通过.' + name + '\n')
            my_sql_result = ''
            status = "通过"
            dic_case = general_tools.op_reseponse_data(api_url, params[i], case_id,response_json_data,detail,my_sql_result, status,project,caseSummary,model)
            return dic_case

        else:
            # 返回值为空的时候
            w.write_log(case_id + '\t' + '接口验证未通过!' + name + '\n')
            my_sql_result = json.dumps(response_json_data, ensure_ascii=False)
            status = "不通过"
            dic_case = general_tools.op_reseponse_data(api_url, params[i], case_id,response_json_data,detail,my_sql_result, status,project,caseSummary,model)
            return dic_case

1.7.2、snb_start_single_verify.py

和测试用例的执行文件,大体相同,有些小的改动,去掉了flowcase.py模块,因为是通过单接口直接进行测试了,不需要再组成测试用例了。

这里就不做过多的解释了,理解了上面的测试用例执行的流程,就不难理解这个了。

import sys, os,socket,time
# from core.flowcase import base
base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(base_path)
reload(sys)
sys.setdefaultencoding('utf-8')
from api_verify.create_case_single_verify import case_pyfile
from core.snb_single_report import HtmlReport
from tools.tools import OpMysql
from api_verify.base_api_request_single_verify import BaseApiRequestVerify
from conf import settings
from core.api_request import ApiRequest
from api_verify.snb_case_single_verify import snb_case_single_verify
from core.sendmail import SendMail


#判断是否是在本地运行,如果在本地运行,选择test1
if socket.gethostname().startswith('DESKTOP'):#DESKTOP
    env='snb_test'
    version='拾年宝'
    api_host=settings.API_HOSTS.get(env)#获取host
    # settings.HOST = settings.HOSTS.get(env)
    host = settings.mysql_envs.get(env).get('HOST')#获取host获取数据的IP地址
    #获取数据库的信息
    users = settings.mysql_envs.get(env).get('db').get('MYSQLUSER')
    password = settings.mysql_envs.get(env).get('db').get('MYSQLPASSWORD')
    port = settings.mysql_envs.get(env).get('db').get('PORT')
    db = settings.mysql_envs.get(env).get('db').get('MYSQLDB')
    modify_zk_port=settings.mysql_envs.get(env).get('modify_zk_port')
    #modify_zk_root = settings.mysql_envs.get(env).get('modify_zk_root')
else:
    #执行start.py的时间,后面需要跟一个参数,这个参数是test*,从而获取到测试环境
    env = sys.argv[1]
    # test1,test2,test3,test4
    api_host=settings.API_HOSTS.get(env)
    host=settings.mysql_envs.get(env).get('HOST')
    users=settings.mysql_envs.get(env).get('db').get('MYSQLUSER')
    password=settings.mysql_envs.get(env).get('db').get('MYSQLPASSWORD')
    port = settings.mysql_envs.get(env).get('db').get('PORT')
    db = settings.mysql_envs.get(env).get('db').get('MYSQLDB')
    modify_zk_port=settings.mysql_envs.get(env).get('modify_zk_port')
    modify_zk_root = settings.mysql_envs.get(env).get('modify_zk_root')
    version = sys.argv[2]#同上,执行start.py的时间,后面第二个参数,也就是版本信息
# op_mysql = OpMysql(host,users,password,db,port)
op_mysql = OpMysql(host,users,password,port,db)  #连接数据库的




case_pyfile.create_py_file()#生成测试用例的.py文件
from api_verify.snb_case_single_verify import snb_case_single_verify
api_request=ApiRequest(api_host)#实例化ApiRequest类
base_api_request_verify = BaseApiRequestVerify(op_mysql,api_request)#实例化baseApiRequest类
#a = base_api_verify.snb_regOrLoginSms_Get(0)


start_time=time.time()
if version=='拾年宝':
    #basecase = Base_Flow_Function(op_mysql, base_api, api_request, modify_zk_port)#测试用例实例化
    base_reg = snb_case_single_verify(base_api_request_verify)#生成的测试用例实例化  base_api_request_verify == base
    case_1 = base_reg.snb_regOrLoginSms_Get_0()
    case_2 = base_reg.snb_regOrLoginSms_Get_1()
    case_3 = base_reg.snb_regOrLoginSms_Get_2()

    #生成报告信息
    case_list = []
    case_list.append(case_1)
    case_list.append(case_2)
    case_list.append(case_3)


end_time=time.time()
# 以下是生成的报告内容
op_mysql.close_mysql()
# 关闭数据库
all = {}
total = len(case_list)
all['all']=total    #用例总数
pass_count = 0  #通过的次数

for r in case_list:
        if r['status']=='通过':
                pass_count+=1
all['ok'] = pass_count#通过的次数
all['fail'] = total - pass_count#失败的次数
all['run_time'] = end_time-start_time
all['case_res']=case_list
report = HtmlReport(all)#实例化产生html类的对象
html_name = report.report()#调用生成html的方法,它返回报告的名字
title = time.strftime('%Y%m%d%H%M%S') + '接口测试报告'
content = '本次运行%s条用例,通过%s条,失败%s条。'%(total,pass_count,total-pass_count)

1.8、单接口测试生成的报告

猜你喜欢

转载自blog.csdn.net/m0_37664730/article/details/84998867