欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

接口测试(四)总结及小技巧笔记

程序员文章站 2022-07-10 11:40:25
这回就不直接贴代码而是讲讲接口测试框架中的一些技巧和suds模块 1.首先来讲讲suds,和request模块不同的是,suds模块不是只调用post和get这两种功能,而是根据接口的不同功能调用不同的模块。具体的可以使用suds.client.Client(接口url),一般来讲具体写成: 这是我 ......

    这回就不直接贴代码而是讲讲接口测试框架中的一些技巧和suds模块

    1.首先来讲讲suds,和request模块不同的是,suds模块不是只调用post和get这两种功能,而是根据接口的不同功能调用不同的模块。具体的可以使用suds.client.client(接口url),一般来讲具体写成:

from suds.client import client
class http_driver():
    def suds_driver(self,url,data,method):
        clients = client(url)
        method = eval("clients.service.{0}({1})".format(method,data))
        result = {}
        result["retinfo"] = str(method.retinfo)
        result["retcode"] = str(method.retcode)
        return result

    这是我这回重写框架中的一部分,将suds模块重新封装,方便调用不同模块,而不是死板的写成固定的某个功能然后if判断调用,既不美观又闲的代码臃肿。

    2.然后再来讲讲sql语法的一些应用,在python代码中sql语句是以str形式存放的,自然也就能使用format模块来灵活运用

sql = 'select * from sms_db_{}.t_mvcode_info_{} where fmobile_no = "{}"'.format(test_dict["sql_package"],test_dict["sql_sheet"],test_dict["moblie"])

    这里的test_dict是我接口中返回的字典数据,根据返回的数据不同,模块的灵活性大大增强。

    3.replace模块。在接口测试中,因为经常会出现只能使用一次的数据。为了方便测试,减少反复修改用例的麻烦,所以我们经常把测试数据中不能重复利用的某些数据参数化,然后再代码中进行替换。而在这个过程中使用的模块,就是replace模块

str.replace(old, new[, max])
# old -- 将被替换的子字符串。
# new -- 新字符串,用于替换old子字符串。
# max -- 可选字符串, 替换不超过 max 次

# 例如:
f data.count("register_phone") >0:
                data = data.replace("register_phone", test_dict["moblie"])

    使用ddt导入参数的同时,检测是否存在参数化的数据。如果有,则进行替换操作,将参数化的数据和调用创建数据模块创建的数据互换,以达到每次测试参数化数据的唯一性。

    4.log模块。这次接口测试中,我发现log日志存在大量重复,基本上每调用1次log模块,打印出来的log日志就多出一条重复。经改正后代码如下

from project_common.file_path import file_path
from configparser import configparser
import logging
import time
class data_logger():
    def __init__(self,name, path="data_test.cfg", section="log_data", level_option="level", format_option="format",
                 encoding="utf-8"):
        """
        默认初始化读取配置文件
        :param file_path:
        :param encoding:
        """
        self.name = name
        self.cf = configparser()
        filepath = file_path + "\project_config\\" + path
        self.cf.read(filepath, encoding)
        self.level = self.cf.get(section = section, option = level_option)
        self.fm = logging.formatter(self.cf.get(section = section, option = format_option))

    def log_write(self):
        """
        log文件创建及读取
        :return:
        """
        # 创建日志文件并设定收集信息级别
        my_logger = logging.getlogger(self.name)
        my_logger.setlevel(self.level)
        # 编辑日志格式并设定输出信息级别
        ch = logging.streamhandler()
        ch.setlevel(self.level)
        ch.setformatter(self.fm)
        # 指定输出到文本渠道
        path = file_path + "\project_log\\"+ time.strftime('%y-%m-%d') + "test.log"
        fh = logging.filehandler(path, encoding="utf-8")
        fh.setlevel(self.level)
        fh.setformatter(self.fm)
        # 渠道
        my_logger.addhandler(ch)
        my_logger.addhandler(fh)

        return my_logger

    要点就是再使用的过程中,不要返回结果,而是返回对象,减少模块的调用。

    4.faker模块。在创建测试数据时,经常需要创建假数据,使用faker模块可以实现这一点

# 常用方法:
# 
# city_suffix():市,县
# 
# country():国家
# 
# country_code():国家编码
# 
# district():区
# 
# geo_coordinate():地理坐标
# 
# latitude():地理坐标(纬度)
# 
# longitude():地理坐标(经度)
# 
# lexify():替换所有问号(“?”)带有随机字母的事件。
# 
# numerify():三位随机数字
# 
# postcode():邮编
# 
# province():省份
# 
# street_address():街道地址
# 
# street_name():街道名
# 
# street_suffix():街、路
# 
# random_digit():0
# ~9
# 随机数
# 
# random_digit_not_null():1
# ~9
# 的随机数
# 
# random_element():随机字母
# 
# random_int():随机数字,默认0
# ~9999,可以通过设置min, max来设置
# 
# random_letter():随机字母
# 
# random_number():随机数字,参数digits设置生成的数字位数
# 
# color_name():随机颜色名
# 
# hex_color():随机hex颜色
# 
# rgb_color():随机rgb颜色
# 
# safe_color_name():随机安全色名
# 
# safe_hex_color():随机安全hex颜色
# 
# bs():随机公司服务名
# 
# company():随机公司名(长)
# 
# company_prefix():随机公司名(短)
# 
# company_suffix():公司性质
# 
# credit_card_expire():随机信用卡到期日
# 
# credit_card_full():生成完整信用卡信息
# 
# credit_card_number():信用卡号
# 
# credit_card_provider():信用卡类型
# 
# credit_card_security_code():信用卡安全码
# 
# currency_code():货币编码
# 
# am_pm():am / pm
# 
# century():随机世纪
# 
# date():随机日期
# 
# date_between():随机生成指定范围内日期,参数:start_date,end_date取值:具体日期或者today, -30
# d, -30
# y类似
# 
# date_between_dates():随机生成指定范围内日期,用法同上
# 
# date_object():随机生产从1970 - 1 - 1
# 到指定日期的随机日期。
# 
# date_this_month():
# 
# date_this_year():
# 
# date_time():随机生成指定时间(1970
# 年1月1日至今)
# 
# date_time_ad():生成公元1年到现在的随机时间
# 
# date_time_between():用法同dates
# 
# future_date():未来日期
# 
# future_datetime():未来时间
# 
# month():随机月份
# 
# month_name():随机月份(英文)
# 
# past_date():随机生成已经过去的日期
# 
# past_datetime():随机生成已经过去的时间
# 
# time():随机24小时时间
# 
# timedelta():随机获取时间差
# 
# time_object():随机24小时时间,time对象
# 
# time_series():随机timeseries对象
# 
# timezone():随机时区
# 
# unix_time():随机unix时间
# 
# year():随机年份
# 
# file_extension():随机文件扩展名
# 
# file_name():随机文件名(包含扩展名,不包含路径)
# 
# file_path():随机文件路径(包含文件名,扩展名)
# 
# mime_type():随机mime
# type
# 
# ascii_company_email():随机ascii公司邮箱名
# 
# ascii_email():随机ascii邮箱
# 
# ascii_free_email():
# 
# ascii_safe_email():
# 
# company_email():
# 
# domain_name():生成域名
# 
# domain_word():域词(即,不包含后缀)
# 
# email():
# 
# free_email():
# 
# free_email_domain():
# 
# f.safe_email():安全邮箱
# 
# f.image_url():随机url地址
# 
# ipv4():随机ip4地址
# 
# ipv6():随机ip6地址
# 
# mac_address():随机mac地址
# 
# tld():网址域名后缀(.com,.net.cn, 等等,不包括.)
# 
# uri():随机uri地址
# 
# uri_extension():网址文件后缀
# 
# uri_page():网址文件(不包含后缀)
# 
# uri_path():网址文件路径(不包含文件名)
# 
# url():随机url地址
# 
# user_name():随机用户名
# 
# isbn10():随机isbn(10
# 位)
# 
# isbn13():随机isbn(13
# 位)
# 
# job():随机职位
# 
# paragraph():随机生成一个段落
# 
# paragraphs():随机生成多个段落,通过参数nb来控制段落数,返回数组
# 
# sentence():随机生成一句话
# 
# sentences():随机生成多句话,与段落类似
# 
# text():随机生成一篇文章(不要幻想着人工智能了,至今没完全看懂一句话是什么意思)
# 
# word():随机生成词语
# 
# words():随机生成多个词语,用法与段落,句子,类似
# 
# binary():随机生成二进制编码
# 
# boolean():true / false
# 
# language_code():随机生成两位语言编码
# 
# locale():随机生成语言 / 国际
# 信息
# 
# md5():随机生成md5
# 
# null_boolean():null / true / false
# 
# password():随机生成密码, 可选参数:length:密码长度;special_chars:是否能使用特殊字符;digits:是否包含数字;upper_case:是否包含大写字母;lower_case:是否包含小写字母
# 
# sha1():随机sha1
# 
# sha256():随机sha256
# 
# uuid4():随机uuid
# 
# first_name():
# 
# first_name_female():女性名
# 
# first_name_male():男性名
# 
# first_romanized_name():罗马名
# 
# last_name():
# 
# last_name_female():女姓
# 
# last_name_male():男姓
# 
# last_romanized_name():
# 
# name():随机生成全名
# 
# name_female():男性全名
# 
# name_male():女性全名
# 
# romanized_name():罗马名
# 
# msisdn():移动台国际用户识别码,即移动用户的isdn号码
# 
# phone_number():随机生成手机号
# 
# phonenumber_prefix():随机生成手机号段
# 
# profile():随机生成档案信息
# 
# simple_profile():随机生成简单档案信息
# 
# 随机生成指定类型数据:
# 
# pybool():
# 
# pydecimal():
# 
# pydict():
# 
# pyfloat():left_digits = 5  # 生成的整数位数,
# 
# right_digits = 2  # 生成的小数位数,
# 
# positive = true  # 是否只有正数
# 
# pyint():
# 
# pyiterable()
# 
# pylist()
# 
# pyset()
# 
# pystr()
# 
# pystruct()
# 
# pytuple()
# 
# ssn():生成身份证号
# 
# chrome():随机生成chrome的浏览器user_agent信息
# 
# firefox():随机生成firefox的浏览器user_agent信息
# 
# internet_explorer():随机生成ie的浏览器user_agent信息
# 
# opera():随机生成opera的浏览器user_agent信息
# 
# safari():随机生成safari的浏览器user_agent信息
# 
# linux_platform_token():随机linux信息
# 
# user_agent():随机user_agent信息

    5.映射。测试接口中必然存在的登录的session或者token,因为登录和登录后的其他操作基本是处于两个用例中,在使用过程中如果不保存登陆后的token,就没法进行登陆后的操作了,这个时候就可以使用映射来处理,映射使用的则是hasattr()、getattr()、setattr()函数

    1) hasattr(object, name)

  判断object对象中是否存在name属性,当然对于python的对象而言,属性包含变量和方法;有则返回true,没有则返回false;需要注意的是name参数是string类型,所以不管是要判断变量还是方法,其名称都以字符串形式传参;getattr和setattr也同样;

>>> 
>>> class a():
    name = 'python'
    def func(self):
        return 'a()类的方法func()'

    
>>> 
>>> hasattr(a, 'name')
true
>>> 
>>> hasattr(a, 'age')
false
>>> 
>>> hasattr(a, 'func')
true
>>>

    2)getattr(object, name[, default])

  获取object对象的属性的值,如果存在则返回属性值,如果不存在分为两种情况,一种是没有default参数时,会直接报错;给定了default参数,若对象本身没有name属性,则会返回给定的default值;如果给定的属性name是对象的方法,则返回的是函数对象,需要调用函数对象来获得函数的返回值;调用的话就是函数对象后面加括号,如func之于func();

  另外还需要注意,如果给定的方法func()是实例函数,则不能写getattr(a, 'func')(),因为fun()是实例函数的话,是不能用a类对象来调用的,应该写成getattr(a(), 'func')();实例函数和类函数的区别可以简单的理解一下,实例函数定义时,直接def func(self):,这样定义的函数只能是将类实例化后,用类的实例化对象来调用;而类函数定义时,需要用@classmethod来装饰,函数默认的参数一般是cls,类函数可以通过类对象来直接调用,而不需要对类进行实例化;

>>> 
>>> class a():
    name = 'python'
    def func(self):
        return 'hello world'

    
>>> 
>>> getattr(a, 'name')
'python'
>>> 
>>> getattr(a, 'age')    # age变量不存在则报错

traceback (most recent call last):
  file "<pyshell#464>", line 1, in <module>
    getattr(a, 'age')
attributeerror: class a has no attribute 'age'
>>> 
>>> getattr(a, 'age', 20)
>>> 
>>> getattr(a, 'func')
<unbound method a.func>
>>> 
>>> getattr(a, 'func')()    # func()函数不能被a类对象调用,所以报错

traceback (most recent call last):
  file "<pyshell#470>", line 1, in <module>
    getattr(a, 'func')()
typeerror: unbound method func() must be called with a instance as first argument (got nothing instead)
>>> 
>>> getattr(a(), 'func')()
'hello world'
>>> 


>>> class a(object):
	    name = 'python'
	    @classmethod
	    def func(cls):
		      return 'the method of a object.'
>>> 
>>> getattr(a, 'func')()
'the method of a object.'
>>>

    3) setattr(object, name, value)

  给object对象的name属性赋值value,如果对象原本存在给定的属性name,则setattr会更改属性的值为给定的value;如果对象原本不存在属性name,setattr会在对象中创建属性,并赋值为给定的value;

>>> 
>>> class a():
    name = 'python'
    def func(self):
        return 'hello world'

    
>>> 
>>> setattr(a, 'name', 'java')
>>> getattr(a, 'name')
'java'
>>> 
>>> setattr(a, 'age', 20)
>>> getattr(a, 'age')
>>>

     扩展:一般先判断对象中是否存在某属性,如果存在则返回;如果不存在,则给对象增加属性并赋值;很简单的if-else判断

>>> 
>>> class a():
    name = 'python'
    def func(self):
        return 'hello world'

    
>>> 
>>> if hasattr(a, 'age'):
    print getattr(a, 'age')
else:
    setattr(a, 'age', 20)

    
>>> 
>>> getattr(a, 'age')
>>>

  

    6.最后就是一些细节需要注意,

    1)cfg文件中一般使用‘ ’而不是“ ”,如果是sql连接则不需要引号,连接中接口必须是int类型,而其他的host,user,password则是str类型

    2)希望sql返回数据是字典类型则可以使用pymysql.cursors.dictcursor,

cursor = self.mysql.cursor(pymysql.cursors.dictcursor)

    3)抛出的异常也可以作为返回值进行判断

 except suds.webfault as e:
            self.log.error("执行sendmcode用例第{}条报错,错误为{}".format(case_id,e))
            error_result = str(e).split(":")[1]
            excel_edit().write_excel(test_function=error_result, case_id=case_id, sheet_name=sheet_name)

    抛出的异常打印为

执行sendmcode用例第4条报错,错误为server raised fault: '短信模板不存在'