httprunner2使用

安装:
pip install httprunner==2.5.9
起一个脚手架:
 hrun --startproject demo  
脚手架框架结构:

运行用例(套件、用例、接口曾都可以运行,一般运行套件层,通过套件层组织用例,用例层组织接口):
hrun api/course_list.yml
 报告查看: 

接口层编写:
name: 课程列表
base_url: http://127.0.0.1:8000
variables:
  token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNjkyNjY2Mzk5LCJlbWFpbCI6ImFkbWluQGFkbWluLmNvbSJ9.kRVtMOx7WKT7ufksGzfhYVdOusDPBoidOGprFKf2lNo
  course_id: 4
request:
    url: /course/viewsets/$course_id
    method: GET
    headers:
        Authorization: 'JWT $token'
validate:
    - eq: ["status_code", 200]
   字段解释:
  1. name:用例名称
  2. base_url:域名
  3. variables:变量,可通过用例层和套件层传入
  4. request:请求信息,变量可参考requests模块
  5. validate:断言
变量取值:

在api文件中设置variables,请求username和password通过$变量名的方式直接取variables中设置的变量名 

用例层编写:
config:
    name: "获取课程列表详情"
    variables:
        username: ${ENV(USERNAME)}
        password: ${ENV(PASSWORD)}
    base_url: "http://127.0.0.1:8000"

teststeps:
-
    name: 登录
    api: api/login.yml
    variables:
        username: $username
        password: $password
    extract:
        - token: content.token
    validate:
        - eq: ["status_code", 200]
-
    name: 课程列表
    api: api/course_list.yml
    variables:
        token: $token
    extract:
        - course_id: content.results.0.id
        - course_name: content.results.0.name
-
    name: 课程详情
    api: api/course_detail.yml
    variables:
        token: $token
        course_id: $course_id
    validate:
        - eq: ['content.name','$course_name']
字段解释:

config:

  1. name:用例名称
  2. variables:配置变量
  3. base_url:域名

teststeps:用例步骤,每个步骤调用一个api yaml文件

api:指定调用api yaml文件路径

extract:提取变量参数,供后面步骤调用

变量取值:

config 和 testteps中的variables名称一样时 优先取config中variables中参数

config中没有设置,取testseps中参数 testcase中参数会覆盖api文件中参数

套件层编写:
config:
    name: "课程套件"
    variables:
      username: ${ENV(USERNAME)}
      password: ${ENV(PASSWORD)}
    base_url: "http://127.0.0.1:8000"

testcases:
-
    name: 查看课程列表
    testcase: testcases/course_testcase.yml
    variables:
        username: $username
        password: $password
-
    name: 添加课程
    testcase: testcases/add_course_testcase.yml
    variables:
        username: $username
        password: $password
字段解释:

config:与用例层字段意义一样

testcases:测试用例,每个测试用例之间相互独立,一个套间可以有多个测试用例

变量优先级:

变量优先级按以下顺序排列:

存在extract提取变量值的,优先取提取中参数content.token

在无extract时,优先取config变量

在无config变量时,优先取用例中变量

以上均无时,取api变量

初始化和清除操作:
yml文件对应代码
config:
    name: "获取课程列表详情"
    variables:
        username: ${ENV(USERNAME)}
        password: ${ENV(PASSWORD)}
    base_url: "http://127.0.0.1:8000"
    setup_hooks: ['${hook_print(用例开始执行)}']
    teardown_hooks: ['${hook_print(用例结束执行)}']

teststeps:
-
    name: 登录
    api: api/login.yml
    variables:
        username: admin1
        password: $password
    setup_hooks: ["${setup_hooks_prepare($request)}"]
    extract:
        - token: content.token
    validate:
        - eq: ["status_code", 200]
-
    name: 课程列表
    api: api/course_list.yml
    variables:
        token: $token
    teardown_hooks: ["${teardown_hooks_res($response)}"]
    extract:
        - course_id: content.results.0.id
        - course_name: content.results.0.name
-
    name: 课程详情
    api: api/course_detail.yml
    variables:
        token: $token
        course_id: $course_id
    validate:
        - eq: ['content.name','$course_name']
debugtalk对应代码:
def hook_print(msg):
    print(msg)

def setup_hooks_prepare(request):
    print('步骤开始执行')
    if request['method']=='POST' and 'data' in request:
        if request.get('headers') is None:request['headers']={}
        request['headers']['Content-Type']='application/json'
        request['data']=json.dumps(request['data'])

def teardown_hooks_res(response):
    print('步骤结束执行')
    if response.resp_obj.status_code==200:
        try:
            data=response.resp_obj.json()

            if 'results' in data:
                data['results'][0].pop('create_at')
                response.resp_obj._content=json.dumps(data).encode('utf8')

        except json.decoder.JSONDecodeError as e:
            pass
终端执行输出:

 一般调用debugtalk方法:${hook_print(用例开始执行)}

如果是hook调用初始化和清除方法:['${hook_print(用例结束执行)}']

值得一提的是如果接口层和用例层调用相同的方法,传入不同的参数,会执行多次,这个是需要注意的点,可以针对代码内容做一个判断,而且会优先执行接口层初始化,

接口层

用例层:

 debugtalk代码及执行输出:

接口层和用例层传入一样参数执行输出,可以看到只执行一层:

 

断言操作:

我们先来看一下httprunner解析yml文件代码:

def get_uniform_comparator(comparator):
    """convert comparator alias to uniform name"""
    if comparator in ["eq", "equals", "==", "is"]:
        return "equals"
    elif comparator in ["lt", "less_than"]:
        return "less_than"
    elif comparator in ["le", "less_than_or_equals"]:
        return "less_than_or_equals"
    elif comparator in ["gt", "greater_than"]:
        return "greater_than"
    elif comparator in ["ge", "greater_than_or_equals"]:
        return "greater_than_or_equals"
    elif comparator in ["ne", "not_equals"]:
        return "not_equals"
    elif comparator in ["str_eq", "string_equals"]:
        return "string_equals"
    elif comparator in ["len_eq", "length_equals", "count_eq"]:
        return "length_equals"
    elif comparator in [
        "len_gt",
        "count_gt",
        "length_greater_than",
        "count_greater_than",
    ]:
        return "length_greater_than"
    elif comparator in [
        "len_ge",
        "count_ge",
        "length_greater_than_or_equals",
        "count_greater_than_or_equals",
    ]:
        return "length_greater_than_or_equals"
    elif comparator in ["len_lt", "count_lt", "length_less_than", "count_less_than"]:
        return "length_less_than"
    elif comparator in [
        "len_le",
        "count_le",
        "length_less_than_or_equals",
        "count_less_than_or_equals",
    ]:
        return "length_less_than_or_equals"
    else:
        return comparator

字符串相关判断代码:

def contains(check_value, expect_value):
    assert isinstance(check_value, (list, tuple, dict, basestring))
    assert expect_value in check_value


def contained_by(check_value, expect_value):
    assert isinstance(expect_value, (list, tuple, dict, basestring))
    assert check_value in expect_value


def type_match(check_value, expect_value):
    def get_type(name):
        if isinstance(name, type):
            return name
        elif isinstance(name, basestring):
            try:
                return __builtins__[name]
            except KeyError:
                raise ValueError(name)
        else:
            raise ValueError(name)

    assert isinstance(check_value, get_type(expect_value))


def regex_match(check_value, expect_value):
    assert isinstance(expect_value, basestring)
    assert isinstance(check_value, basestring)
    assert re.match(expect_value, check_value)


def startswith(check_value, expect_value):
    assert builtin_str(check_value).startswith(builtin_str(expect_value))


def endswith(check_value, expect_value):
    assert builtin_str(check_value).endswith(builtin_str(expect_value))

eq: 判断是否相等

lt: 小于

le:小于等于

gt:大于

ge:大于等于

ne:不等于

contains && contains by : 包含和被包含

regex_match: expect_value写一个正则表达式,如果实际结果能正则表达式匹配成功,需要注意的是re.match和re.search是不一样的,match代表正则表达式必须从实际结果字符串开始的地方匹配,如果需要更复杂的场景,可以把httprunner源码copy到项目目录下,将match修改成search

starswith && endswith: 实际结果以期望结果开头、结尾

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值