首页 > 其他分享 >关键字 开发-13 API与用例分层

关键字 开发-13 API与用例分层

时间:2023-12-20 16:11:06浏览次数:36  
标签:API 13 name request value 用例 step api

前言

前面我们都是在yml文件中写单个用例的去调用,如果后期涉及到业务流程的时候,单个用例就无法满足需要测试的业务流程。如何实现这个功能,我们可以将用例和api进行分离,api层只写单个接口的数据,然后在用例层处理业务流程,不断的调用api的接口,从而可以满足我们的需求。那么这篇将讲如何在yml文件中实现接口业务流程的测试。

1. API层

我们创建api文件夹,存放api的接口信息,创建testcase文件夹,存放test业务用例,实现api和用例的分离。

1.api层:描述接口 request 请求,可以带上 validate 基本的校验
2.testcase用例层: 用例层调用多个api并通过顺序引用,实现业务流程

如图可以清楚的知道实现的原理,不同的testcase中可以调用多个api,实现用例业务流程。

# api/login.yml
name: 登录api
request:
  url: /api/v1/auth/login
  method: POST
  json:
    username: ${username}
    password: ${password}
extract:
  code1: $.code
  code2: body.code
  token: $.data.token
  msg: '"message":"(.*?)"'
validate:
  - eq: [$.code, "000000"]
  - eq: [$.message, OK]

api层的login.yml文件,可以实现接口的信息,请求,以及可以提取接口返回的值,并也支持接口的校验,同时如果需要引用变量,也可以支持jinja2语法。比如登录用户名密码在不同用例中会用到不同的账号,那么可以使用变量\({username},\){password}。需注意的是,API层不支持单独运行,因为它只是记录用例的接口信息部分,不能当成用例去执行,用例执行需使用 test_*.yml命名。

2.testcase层

用例层通过api关键字导入需要的API,导入的路径是相对路径,需根据项目的根目录去导入。如果执行过程中代码无法识别哪个是项目根目录,最好在项目的根目录下放pytest.ini 文件,pytest会以pytest.ini文件所在的目录为项目根目录。
项目的目录如下所示:
├─api └─ login.yml ├─testcase └─ test_login.yml └─conftest.py └─pytest.ini
所以不管用例文件test_*.yml在哪个目录,都是以项目根目录去导入API的yaml文件。如下登录用例层:在config中可以传入请求时需要的参数,teststeps表示用例的执行步骤,通过-分割步骤1和步骤2。例子中实现了登录-步骤1以及登录-步骤2,2个步骤都是从login.yml中获取到api的信息,从而实现多个步骤的业务流程用例。

# testcase/test_login.yml
config:
  name: 登录用例
  variables:
    username: "admin"
    password: "Admin@22"

teststeps:
  -
    name: 登录-步骤1
    api: api/login.yml
    extract:
      code1: $.code
      code2: body.code
      token: $.data.token
    validate:
      - eq: [$.code, "000000"]
      - eq: [status_code, 200]

  -
    name: 登录-步骤2
    api: api/login.yml
    validate:
      - eq: [ status_code, 200 ]

3.API和用例分层功能实现

如下所示的实现功能的代码块,对代码块进行讲解:

1.从def execute_yaml_case用例函数这里开始,这是实现每个用例的testcae函数
2.上面已经将收集到的全部test_*.yml用例放入case中,于是用例中通过case[call_function_name],拿到每个testcase,如:{"teststeps",{[...],[...]}}
3.teststeps有多个步骤,使用for循环获取多个步骤,分别请求处理:for step in case[call_function_name]:
4.再通过for item, value in step.items():处理每个步骤总的关键字参数
5.判断elif item == 'api':处理api:1-实现通过相对路径获取到API层的api信息,2-深拷贝一份新的request,单独处理request请求,3-渲染request的变量,4-单独封装run_request请求。

        case = {}  # 收集用例名称和执行内容
          ......

            def execute_yaml_case(args):
                """执行yaml 中用例部分,根据这个函数动态生成其他测试用例函数"""
                log.info(f"执行的参数: {args}")
                # 更新fixtures的返回值,到容器中
                self.context.update(args)

                # 被谁调用
                call_function_name = inspect.getframeinfo(inspect.currentframe().f_back)[2]
                log.info(f'执行的内容: {case[call_function_name]}')
                for step in case[call_function_name]:
                    step_context = self.context.copy()
                    step_name = step.get('name')
                    if step_name:
                        log.info(f'用例执行:{step_name}')
                        step_name = render_template_obj.rend_template_any(step_name, **step_context)
                    if 'validate' not in step.keys():
                        step['validate'] = []
                    
                    for item, value in step.items():
                      # 根据关键字去执行
                      if item == 'name':
                          pass
                      elif item == 'print':
                          log.info(value)
                      elif item == 'api':
                          # 通过hook函数:内置request获取到项目的根路径
                          root_dir = args.get('request').config.rootdir
                          # 获取文件路径
                          api_path = Path(root_dir).joinpath(value)
                          raw_api = yaml.safe_load(api_path.open(encoding='utf-8'))
                          api_validate = raw_api.get('validate', [])
                          copy_value = copy.deepcopy(raw_api.get('request'))  # 深拷贝一份新的value
                          # 渲染变量
                          copy_value = render_template_obj.rend_template_any(copy_value, **self.context)
                          BASE_URL_api = base_url if base_url else args.get('base_url')
                          response = self.run_request(args, copy_value, BASE_URL_api, context=step_context)

......

    def run_request(self, args, copy_value, base_url, context=None):
        """运行request请求"""
        request_session = args.get('requests_function') or args.get('requests_module') or args.get('requests_session')
        # 加载参数化的值和fixture的值
        if context is None:
            request_value = render_template_obj.rend_template_any(copy_value, **self.context)
        else:
            request_value = render_template_obj.rend_template_any(copy_value, **context)
        response = request_session.send_request(base_url=base_url, **request_value)
        return response

根目录下运行:pytest testcase,如图所示,运行成功,登录用例包含了2个步骤。

标签:API,13,name,request,value,用例,step,api
From: https://www.cnblogs.com/dack-zt-deng/p/17916711.html

相关文章

  • HTML5新增标签及API
    之前有一天看到了这样的一段代码,居然可以使用dom的id直接调用方法和获取属性,真是刷新了我的认知了。<div><pid="content">aa</p><buttononclick="console.log(content.innerText)">打印内容</button></div> 点击按钮,控制台就可以打印出aa字符串习惯写后端的我前......
  • APIView源码分析
    1.和CBV源码执行流程相似,请求来了先走路由层:path('books/',views.BookView.as_view()) 2.走APIView的as_view方法,代码如下:@classmethoddefas_view(cls,**initkwargs):view=super().as_view(**initkwargs)#调用父类的as_view,view还是View的as_view......
  • 测试用例设计方法六脉神剑——第六剑:心法至简,百家之长集成
    1引言在前面几篇文章中,为大家介绍的都是系统的方法论,但在实际需求测试的过程当中,受到外部环境及业务逻辑的影响,比如涉及多需求耦合、浏览器缓存堆积等情况,仅针对当前需求设计出的测试用例就会有覆盖不全的问题,此时就需要借助以往的经验进行反向错误推测,辅助其他方法对测试用例进......
  • api熔断
    简介:在C#中,API熔断是指在使用某个API时,如果该API的响应时间或错误率超过了预设的阈值,系统会自动停止对该API的请求,并返回一个预设的错误信息,以防止由于API的故障或超时导致整个系统出现故障或降级。具体实现方式可以采用以下几种方法:计数器熔断:在客户端维护一个计......
  • 【全志T113-i】OK113i-S开发板-2适配10寸LCD显示
     前言本文介绍如何在OK113i-S开发板上适配一个自己的10寸LCD。OK113i-S是一个优秀的开发板,支持lvds单8,双8显示,最大分辨率1280x800也支持RG666显示,由于我手头只有lvds单8,40pin的显示器,今天我就适配一下这个LCD的显示。显示效果编辑设备接线我这个转接板是两部分,左边的是触摸线,右......
  • 每日导数13
    越复杂越简单,构造问题已知函数\(f(x)=(\lnx-2x+a)\lnx\)\((1)\)当\(a=2\)时,求\(f(x)\)的单调性\((2)\)若\(f(x)\leq\dfrac{e^x}{x}-x^2+ax-a\),求实数\(a\)的取值范围.解\((1)\)\(a=2,f(x)=(\lnx-2x+2)\lnx=\ln^2x-2x\lnx+2\lnx\)\(f^{\prime}(x)=\dfrac{2\ln......
  • Midjourney模拟API生图调用
    目前Midjourney没有对外开放API接口,所以通过MJ自动化生图的主要方式是,集成Discord应用机器人,通过机器人与MJ机器人进行交互,并监听频道内的生图结果,最终拿到图片地址。简单介绍下步骤一、购买MJ账号二、获取账号Authorization在网页中向MidjourneyBot发送/imagine进行生图我......
  • 13.元素定位工具
    uiautomatorviewer工具安装工具的安装:AndroidSDK自带的界面分析工具打开 tools/bin 目录下的 uiautomatorviewer 程序uiautomatorviewer工具功能介绍第一个是通过分析给定的文件定位第二个是将当前界面截图并分析xml结构第三个与第二个功能类似,但它会对页面内容......
  • CF1913 E Matrix Problem 题解
    LinkCF1913EMatrixProblemQuestion给定一个\(n\timesm\)的01矩阵,你可以把矩阵中的任意一个元素01翻转需要最后的矩阵满足,每行\(1\)的个数有\(A[i]\)个,每列\(1\)的个数有\(B[i]\)个Solution这貌似是一道非常经典的费用流题目我们建立\(n\)个行节点,\(m......
  • API 接口设计最佳实践
    前言 最近团队内部在做故障复盘的时候发现有很多故障都是因为接口设计不当导致的,这里我就整理归纳一下在接口设计层面需要注意的地方。API接口设计Token设计 Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此To......