• Python+requests编写的自动化测试项目


    框架产生目的:公司走的是敏捷开发模式,编写这种框架是为了能够满足当前这种发展模式,用于前后端联调之前(后端开发完接口,前端还没有将业务处理完毕的时候)以及日后回归阶段,方便为自己腾出学(mo)习(yu)时间。

    鄙人一介小测试,一手承接产品,一手面对开发(4个后端,3个web前端,外加不知道几个的乙方),项目经手了5批人,鄙人是第5批的测试,规范没有,前人积累没有,天崩开局/(ㄒoㄒ)/~~。

    老规矩,上图:

    这个不直观,下面我来展示这个抽象的图片(美术功底差,见谅):

    怎么,是不是有一种UI自动化里面的POM思想?没错,这正是这个思路在API自动化里里面的一个体现。

    毕竟服务间的调用是复杂的,将各个接口封装起来,对应的py文件里面创一个main方法,用于单个接口入参以及返回值之间的验证,至于接口之间的串联,那就放到下面(regression_test里面,每一个case相当于一个过程,如:上传习题、选题、组卷分发、上传试卷、批阅等流程),辅以逻辑处理,大部分的流程还是可以自动化实现的(ps:对于前后端联调加改bug用了两个月时间才圆满搞定的过程,我没敢尝试将这个给自动化实现了,还是留待后人吧)。

    getpathInfo.py:获取autoapi文件夹所在的目录,便于项目换家,有没有其实无所谓的;

    1. import os
    2. def get_path():
    3. path = os.path.split(os.path.realpath(__file__))[0]
    4. return path
    5. if __name__ == '__main__':
    6. print('测试路径是否OK,路径为:', get_path())

    readConfig.py

    1. import os
    2. import configparser
    3. import getpathInfo
    4. path = getpathInfo.get_path()
    5. config_path = os.path.join(path, 'config')
    6. config = configparser.ConfigParser() # 调用外部的读取配置文件的方法
    7. config.read(config_path, encoding='utf-8')
    8. class ReadConfig():
    9. def get_http(self, name):
    10. value = config.get('HTTP', name)
    11. return value
    12. def get_email(self, name):
    13. value = config.get('EMAIL', name)
    14. return value
    15. def get_account(self, name):
    16. value = config.get('ACCOUNT', name)
    17. return value
    18. environment = ReadConfig().get_http('environment') # 切换环境
    19. mobile_phone = ReadConfig().get_account('mobile_phone')
    20. password = ReadConfig().get_account('password')
    21. parent_username = ReadConfig().get_account('parent_phone')
    22. parent_pwd = ReadConfig().get_account('parent_pwd')

    common:公共方法文件夹,最省事配置:日志封装(中文日志在这里要留意,有坑),请求封装(如果有token之类的限制的话)

    logs.py

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    import logging

    import time

    from getpathInfo import get_path

    class Log(object):

        def __init__(self, logger=None):

            """

            指定保存日志的文件路径,日志级别,以及调用文件

            将日志存入到指定的文件中

            """

            # 创建一个logger

            self.logger = logging.getLogger(logger)

            self.logger.setLevel(logging.DEBUG)

            # 创建一个handler,用于写入日志文件

            self.log_time = time.strftime('%Y-%m_%d_')

            self.log_path = get_path()+'\\log\\'

            self.log_name = self.log_path + self.log_time + 'test.log'

            fh = logging.FileHandler(self.log_name, 'a', encoding='utf-8')  # 追加模式,防止中文乱码

            fh.setLevel(logging.INFO)

            # 再创建一个handler,用于输出到控制台

            ch = logging.StreamHandler()

            ch.setLevel(logging.INFO)

            # 定义一个handler的输出样式

            formatter = logging.Formatter(

                '[%(asctime)s] %(filename)s->%(funcName)s line:%(lineno)d [%(levelname)s]%(message)s')

            fh.setFormatter(formatter)

            ch.setFormatter(formatter)

            # 给logger添加handler

            self.logger.addHandler(fh)

            self.logger.addHandler(ch)

            #  添加下面一句,在记录日志之后移除句柄

            fh.close()

            ch.close()

        def getLog(self):

            return self.logger

    log = Log().getLog()

    if __name__ == '__main__':

        log.info('日志')  # 抄过来的代码一定要进行测试

    configHttp.py

    这里是默认加上token的,但是并不是所有接口都是需要token,解决思路:再加个configHttpNormal.py。对于同一个系统中需要多个用户参与的过程,这时候就需要配置文件里面再多一位用户的账号密码了,再加一个login()方法并赋值,下面的对应的基础请求封装里面要再多一个参数:is_other_one,默认为false,一但给true,下面headers就要换参数中的值;

    1. import json
    2. import requests
    3. from common.logs import log
    4. from readConfig import environment,mobile_phone,password
    5. from case.api.User import login
    6. import urllib3
    7. urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # 如果有抓包需求,需要把verify设置成False,这行代码忽略系统之后的警告
    8. """
    9. 这个文件主要来通过get、post等方法来进行http请求,并拿到请求响应
    10. """
    11. token = login(mobile_phone,password) # 登录方法
    12. headers = {'Authorization': token,
    13. "Content-Type": 'application/json;charset=UTF-8',
    14. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36'}
    15. class RunMain():
    16. def send_post(self, path, data):
    17. response = requests.post(url=environment+path,data=json.dumps(data,ensure_ascii=False,separators=(',',':')).encode('utf-8'), headers=headers,verify=False)
    18. log.info(path)  # path
    19. log.info(data)  # 请求,便于复现
    20. log.info(response.status_code)  # 请求状态码
    21. return response
    22. def send_get(self, path, data):
    23. response = requests.get(url=environment+path, data=data, headers=headers,verify=False)
    24. log.info(path)
    25. log.info(data)
    26. log.info(response.status_code)
    27. return response
    28. def run_main(self, method, path=None, data=None):
    29. result = None
    30. if method.lower() == 'post':
    31. result = self.send_post(path, data)
    32. elif method.lower() == 'get':
    33. result = self.send_get(path, data)
    34. else:
    35. print("method值错误!!!")
    36. return result
    37. if __name__ == '__main__':
    38. result1 = RunMain().run_main('get', '/v1/wrong-work/info?type=1').json()
    39. result2 = RunMain().run_main('Get', '/v1/wrong-work/info?type=2').json()
    40. print(result1)
    41. print(result2)

    case:用例文件夹,敏捷模式中开发提测基本上都是单接口提测,而且同一个模块下的接口分给了不同的开发,为了方便定位到开发,所以我将平台所有的接口都写了过来╮(╯▽╰)╭,

    老规矩,下方直接执行,可以进行单接口的相关验证。

    相信各位也看了很多的接口自动化测试框架,我上面的应该没有多少新意,下面就是不同点;

    regression_testing 顾名思义,回归测试ing,只有进行时,没有完成时……

    鄙人将前端的业务逻辑通过接口层模拟了过来,做了许久之后,不禁产生了怀疑:这都是哪位鬼才设计的?没有被开发XX了吗?

    上图是使用unittest框架进行的,用例之间传参用法其实就是我上面展示的一部分;

    其实这个文件夹下不适合使用unittest框架,因为通过用例之间的巧妙设计,虽然可以将业务之间的调用状态都模拟出来,但是由于脏数据的存在,某些bug没有在这些测试过程中表示出来。

    哎,苦命啊,前端赶紧进行插桩操作,报错日志上传起来;鄙人只能放大招了,拾起了爬虫思路,自动遍历吧(穷举);

    放代码片段,哎,遍历一时爽,重构火葬场(json目录深了之后,是真的不想看)。

    之后优化思路:将regression_testing里面的方法改成test_*,写一个run方法,加上测试报告,邮件通知(ps:但鄙人不用啊,就十个人,遇到bug,tapd复制上参数,“老哥,出bug了”)

    是不是也发现了,少了很多东西?写个装饰器(用于统计时间),接口请求超时也要打印出来;

     其实还有一个文件夹,用来写压测脚本(基于locust的FasthttpUser),log文件夹中的path以及data都是直接可以在locust中使用的,省了构造数据的时间;

    locust脚本如下(部分),更详细的可以看看httprunner的实现思路,大神写的比我强太多了,还是得学啊。

    【整整200集】超超超详细的Python接口自动化测试进阶教程合集,真实模拟企业项目实战

  • 相关阅读:
    C++简单实现内存池原理
    为什么使用Hooks?
    手撕红黑树 | 变色+旋转你真的明白了吗?【超用心超详细图文解释 | 一篇学会Red_Black_Tree】
    【Mybatis小白从0到90%精讲】07:Mybatis 传递参数方式详解
    Azure vs. AssemblyAI:深度解析语音转文本服务的对决
    《最新出炉》系列初窥篇-Python+Playwright自动化测试-11-playwright操作iframe-上篇
    洛谷 模板汇总 算法基础 python解析
    Linux进程信号
    kubeasz一键部署k8s集群
    js实现高度自动的过渡动画
  • 原文地址:https://blog.csdn.net/dad22211/article/details/132879230