百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

接口自动化测试框架开发(Pytest+Allure+AIOHTTP+用例自动生成上

ccwgpt 2024-10-11 11:24 43 浏览 0 评论

近期准备做接口测试的覆盖,为此需要开发一个测试框架,思考了以下几个特性要求:

  • 接口测试是比较讲究效率的,测试人员会希望很快能得到结果反馈,然而接口的数量一般都很多,而且会越来越多,所以提高执行效率很有必要;
  • 接口测试的用例其实也可以用来兼做简单的压力测试,而压力测试需要并发;
  • 接口测试的用例有很多重复的东西,测试人员应该只需要关注接口测试的设计,这些重复劳动最好自动化来做;
  • Pytest 和 Allure 太好用了,新框架要集成它们;
  • 接口测试的用例应该尽量简洁,最好用 yaml,这样数据能直接映射为请求数据,写起用例来跟做填空题一样,便于向没有自动化经验的成员推广;
  • 加上我对 Python 的协程很感兴趣,也学了一段时间,一直希望学以致用,所以 HTTP 请求我决定用 AIOHTTP 来实现;
  • 但是 pytest 是不支持事件循环的,如果想把它们结合还需要一番功夫。

于是继续思考,思考的结果是其实我可以把整个事情分为两部分;

第一部分,读取 yaml 测试用例,HTTP 请求测试接口,收集测试数据。第二部分,根据测试数据,动态生成 pytest 认可的测试用例,然后执行,生成测试报告。

这样一来,两者就能完美结合了,也完美符合我所做的设想。接着就来实现它。

第一部分(整个过程都要求是异步非阻塞的)

读取 yaml 测试用例

一份简单的用例模板我是这样设计的,这样的好处是,参数名和 aioHTTP.ClientSession().request(method,url,**kwargs) 是直接对应上的,我可以不费力气的直接传给请求方法,避免各种转换,简洁优雅,表达力又强。

args:
  - post
  - /xxx/add
kwargs:
  -
    caseName: 新增 xxx
    data:
      name: ${gen_uid(10)}
validator:
  -
    json:
      successed: True

异步读取文件可以使用 aiofiles 这个第三方库,yaml_load 是一个协程,可以保证主进程读取 yaml 测试用例时不被阻塞,通过await yaml_load()便能获取测试用例的数据

async def yaml_load(dir='', file=''):
    """
    异步读取 yaml 文件,并转义其中的特殊值
    :param file:
    :return:
    """
    if dir:
        file = os.path.join(dir, file)
    async with aiofiles.open(file, 'r', encoding='utf-8', errors='ignore') as f:
        data = await f.read()

    data = yaml.load(data)

    # 匹配函数调用形式的语法
    pattern_function = re.compile(r'^\${([A-Za-z_]+\w*\(.*\))}#39;)
    pattern_function2 = re.compile(r'^\${(.*)}#39;)
    # 匹配取默认值的语法
    pattern_function3 = re.compile(r'^\$\((.*)\)#39;)

    def my_iter(data):
        """
        递归测试用例,根据不同数据类型做相应处理,将模板语法转化为正常值
        :param data:
        :return:
        """
        if isinstance(data, (list, tuple)):
            for index, _data in enumerate(data):
                data[index] = my_iter(_data) or _data
        elif isinstance(data, dict):
            for k, v in data.items():
                data[k] = my_iter(v) or v
        elif isinstance(data, (str, bytes)):
            m = pattern_function.match(data)
            if not m:
                m = pattern_function2.match(data)
            if m:
                return eval(m.group(1))
            if not m:
                m = pattern_function3.match(data)
            if m:
                K, k = m.group(1).split(':')
                return bxmat.default_values.get(K).get(k)

            return data

    my_iter(data)

    return BXMDict(data)

可以看到,测试用例还支持一定的模板语法,如${function}、$(a:b)等,这能在很大程度上拓展测试人员用例编写的能力

HTTP 请求测试接口

HTTP 请求可以直接用aioHTTP.ClientSession().request(method,url,**kwargs),HTTP 也是一个协程,可以保证网络请求时不被阻塞,通过await HTTP()便可以拿到接口测试数据

async def HTTP(domain, *args, **kwargs):
    """
    HTTP 请求处理器
    :param domain: 服务地址
    :param args:
    :param kwargs:
    :return:
    """
    method, api = args
    arguments = kwargs.get('data') or kwargs.get('params') or kwargs.get('json') or {}

    # kwargs 中加入 token
    kwargs.setdefault('headers', {}).update({'token': bxmat.token})
    # 拼接服务地址和 api
    url = ''.join([domain, api])

    async with ClientSession() as session:
        async with session.request(method, url, **kwargs) as response:
            res = await response_handler(response)
            return {
                'response': res,
                'url': url,
                'arguments': arguments
            }
收集测试数据

协程的并发真的很快,这里为了避免服务响应不过来导致熔断,可以引入asyncio.Semaphore(num)来控制并发

async def entrace(test_cases, loop, semaphore=None):
    """
    HTTP 执行入口
    :param test_cases:
    :param semaphore:
    :return:
    """
    res = BXMDict()
    # 在 CookieJar 的 update_cookies 方法中,如果 unsafe=False 并且访问的是 IP 地址,客户端是不会更新 cookie 信息
    # 这就导致 session 不能正确处理登录态的问题
    # 所以这里使用的 cookie_jar 参数使用手动生成的 CookieJar 对象,并将其 unsafe 设置为 True
    async with ClientSession(loop=loop, cookie_jar=CookieJar(unsafe=True), headers={'token': bxmat.token}) as session:
        await advertise_cms_login(session)
        if semaphore:
            async with semaphore:
                for test_case in test_cases:
                    data = await one(session, case_name=test_case)
                    res.setdefault(data.pop('case_dir'), BXMList()).append(data)
        else:
            for test_case in test_cases:
                data = await one(session, case_name=test_case)
                res.setdefault(data.pop('case_dir'), BXMList()).append(data)

        return res


async def one(session, case_dir='', case_name=''):
    """
    一份测试用例执行的全过程,包括读取 .yml 测试用例,执行 HTTP 请求,返回请求结果
    所有操作都是异步非阻塞的
    :param session: session 会话
    :param case_dir: 用例目录
    :param case_name: 用例名称
    :return:
    """
    project_name = case_name.split(os.sep)[1]
    domain = bxmat.url.get(project_name)
    test_data = await yaml_load(dir=case_dir, file=case_name)
    result = BXMDict({
        'case_dir': os.path.dirname(case_name),
        'api': test_data.args[1].replace('/', '_'),
    })
    if isinstance(test_data.kwargs, list):
        for index, each_data in enumerate(test_data.kwargs):
            step_name = each_data.pop('caseName')
            r = await HTTP(session, domain, *test_data.args, **each_data)
            r.update({'case_name': step_name})
            result.setdefault('responses', BXMList()).append({
                'response': r,
                'validator': test_data.validator[index]
            })
    else:
        step_name = test_data.kwargs.pop('caseName')
        r = await HTTP(session, domain, *test_data.args, **test_data.kwargs)
        r.update({'case_name': step_name})
        result.setdefault('responses', BXMList()).append({
            'response': r,
            'validator': test_data.validator
        })

    return result

事件循环负责执行协程并返回结果,在最后的结果收集中,我用测试用例目录来对结果进行了分类,这为接下来的自动生成 pytest 认可的测试用例打下了良好的基础。

def main(test_cases):
    """
    事件循环主函数,负责所有接口请求的执行
    :param test_cases:
    :return:
    """
    loop = asyncio.get_event_loop()
    semaphore = asyncio.Semaphore(bxmat.semaphore)
    # 需要处理的任务
    # tasks = [asyncio.ensure_future(one(case_name=test_case, semaphore=semaphore)) for test_case in test_cases]
    task = loop.create_task(entrace(test_cases, loop, semaphore))
    # 将协程注册到事件循环,并启动事件循环
    try:
        # loop.run_until_complete(asyncio.gather(*tasks))
        loop.run_until_complete(task)
    finally:
        loop.close()

    return task.result()



想看第二篇文章可继续看下文。

(文章来源于霍格沃兹测试学院)

相关推荐

自己动手写Android数据库框架_android开发数据库搭建

http://blog.csdn.net/feiduclear_up/article/details/50557590推荐理由关于Android数据库操作,由于每次都要自己写数据库操作,每次还得去...

谷歌开源大模型评测工具LMEval,打通谷歌、OpenAI、Anthropic

智东西编译|金碧辉编辑|程茜智东西5月28日消息,据科技媒体TheDecoder5月26日报道,当天,谷歌正式发布开源大模型评测框架LMEval,支持对GPT-4o、Claude3.7...

工信部:着力推动大模型算法、框架等基础性原创性的技术突破

工信部新闻发言人今日在发布会上表示,下一步,我们将坚持突出重点领域,大力推动制造业数字化转型,推动人工智能创新应用。主要从以下四个方面着力。一是夯实人工智能技术底座。通过科技创新重大项目,着力推动大模...

乒乓反复纠结“框架不稳定”的三个小误区

很多球友由于对框架的认知不清晰,往往会把“框架不稳定”当成一种心理负担,从而影响学球进度,其典型状态就是训练中有模有样,一旦进入实战,就像被捆住了手脚。通过训练和学习,结合“基本功打卡群”球友们交流发...

前AMD、英特尔显卡架构师Raja再战GPU,号称要全面重构堆栈

IT之家8月5日消息,知名GPU架构师拉贾科杜里(RajaKoduri)此前曾先后在AMD和英特尔的显卡部门担任要职。而在今日,由Raja创立的GPU软件与IP初创企...

三种必须掌握的嵌入式开发程序架构

前言在嵌入式软件开发,包括单片机开发中,软件架构对于开发人员是一个必须认真考虑的问题。软件架构对于系统整体的稳定性和可靠性是非常重要的,一个合适的软件架构不仅结构清晰,并且便于开发。我相...

怪不得别人3秒就知道软考案例怎么做能50+

软考高级统一合格标准必须三科都达到45分,案例分析也一直是考生头疼的一门,但是掌握到得分点,案例能不能50+还不是你们说了算吗?今天就结合架构案例考点,分享实用的备考攻略~一、吃透考点,搭建知识框架从...

UML统一建模常用图有哪些,各自的作用是什么?一篇文章彻底讲透

10万+爆款解析:9大UML图实战案例,小白也能秒懂!为什么需要UML?UML(统一建模语言)是软件开发的“蓝图”,用图形化语言描述系统结构、行为和交互,让复杂需求一目了然。它能:降低沟通成本避...

勒索软件转向云原生架构,直指备份基础设施

勒索软件组织和其他网络犯罪分子正越来越多地将目标对准基于云的备份系统,对久已确立的灾难恢复方法构成了挑战。谷歌安全研究人员在一份关于云安全威胁演变的报告中警告称,随着攻击者不断改进数据窃取、身份泄露和...

ConceptDraw DIAGRAM:释放创意,绘就高效办公新未来

在当今数字化时代,可视化工具已成为提升工作效率和激发创意的关键。ConceptDrawDIAGRAM,作为一款世界顶级的商业绘图软件,凭借其强大的功能和用户友好的界面,正逐渐成为众多专业人士的首选绘...

APP 制作界面设计教程:一步到位_app界面设计模板一套

想让APP界面设计高效落地,无需繁琐流程,掌握“框架搭建—细节填充—体验优化”三步法,即可一步到位完成专业级设计。黄金框架搭建是基础。采用“三三制布局”:将屏幕横向三等分,纵向保留三...

MCP 的工作原理:关键组件_mcp部件

以下是MCP架构的关键组件:MCP主机:像ClaudeDesktop、GitHubCopilot或旅行助手这样的AI智能体,它们希望通过MCP协议访问工具、资源等。MCP主机会...

软件架构_软件架构师工资一般多少

软件架构师自身需要是程序员,并且必须一直坚持做一线程序员。软件架构应该是能力最强的一群程序员,他们通常会在自身承接编程任务的同时,逐渐引导整个团队向一个能够最大化生产力的系统设计方向前进。软件系统的架...

不知不觉将手机字体调大!老花眼是因为“老了吗”?

现在不管是联系、交友,还是购物,都离不开手机。中老年人使用手机的时间也在逐渐加长,刷抖音、看短视频、发朋友圈……看手机的同时,人们也不得不面对“视力危机”——老花眼,习惯眯眼看、凑近看、瞪眼看,不少人...

8000通用汉字学习系列讲座(第046讲)

[表声母字]加(续)[从声汉字]伽茄泇迦枷痂袈笳嘉驾架咖贺瘸(计14字)嘉[正音]标准音读jiā。[辨形]上下结构,十四画。会意形声字,从壴从加,加也表声。注:从壴,字义与鼓乐有关;从加,字义与...

取消回复欢迎 发表评论: